您的位置:首页 > 大数据 > 人工智能

2016 Multi-University Training Contest 5

2016-08-03 13:17 330 查看

1003

http://acm.hdu.edu.cn/showproblem.php?pid=5783

Divide the Sequence

Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 2232    Accepted Submission(s): 628


[align=left]Problem Description[/align]
Alice has a sequence A, She wants to split A into as much as possible continuous subsequences, satisfying that for each subsequence, every its prefix sum is not small than 0.
 

[align=left]Input[/align]
The input consists of multiple test cases.

Each test case begin with an integer n in a single line.

The next line contains n
integers A1,A2⋯An.
1≤n≤1e6
−10000≤A[i]≤10000

You can assume that there is at least one solution.
 

[align=left]Output[/align]
For each test case, output an integer indicates the maximum number of sequence division.
 

[align=left]Sample Input[/align]

6
1 2 3 4 5 6
4
1 2 -3 0
5
0 0 0 0 0

 

[align=left]Sample Output[/align]

6
2
5

 
题目意思是把一个序列分成尽量多的序列,使得每个序列的前缀和大于等于0。(另外,题目数据保证每个[1, i]的前缀和大于等于0,并且一定有解)

因为忽略了括号里的条件,我觉得这是个dp问题,简单题,然后就tle了,顺手记一下dp的程序:

dp[i]表示[1, i]最多能形成多少个段。那么转移方程如下:

dp[i] = Max(dp[i], dp[j - 1] + (sum[i] - sum[j - 1] >= 0));

<span style="font-size:18px;">//#include<bits/stdc++.h>
#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<time.h>
#include<map>
#include<set>
using namespace std;
//#define ONLINE_JUDGE
#define eps 1e-8
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
#define INFL 0x3f3f3f3f3f3f3f3fLL
#define enter putchar(10)
#define rep(i,a,b) for(int i = (a); i < (b); ++i)
#define repe(i,a,b) for(int i = (a); i <= (b); ++i)
#define mem(a,b) (memset((a),b,sizeof(a)))
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfd(a,b) printf("%d %d\n",a,b)
#define pfP(a) printf("%d %d\n",a.fi,a.se)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%I64d\n",a)
#define ds(a) int a; sf(a)
#define PR(a,b) pair<a,b>
#define fi first
#define se second
#define LL long long
#define DB double
const double PI = acos(-1.0);
const double E = exp(1.0);
template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
template<class T> inline T Min(T a, T b) { return a < b ? a : b; }
template<class T> inline T Max(T a, T b) { return a > b ? a : b; }
int n, m;
const int N = (1e+6) + 10;
int sum
;
int dp
;

void check() {
repe(i, 1, n) {
printf("%d ", dp[i]);
}
enter; enter;
}

int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
//    freopen("Out.txt", "w", stdout);
#endif
while(~sf(n)) {
mem(dp, 0);
sum[0] = 0;
repe(i, 1, n) {
sf(sum[i]);
sum[i] += sum[i - 1];
}
repe(i, 1, n) {
repe(j, i, n) {
if(sum[j] - sum[i - 1] >= 0) dp[j] = Max(dp[j], dp[i - 1] + 1);
}
}
pf(dp
);
}
return 0;
}</span>


后来发现是tle,我想,这个dp好像没法变成一维(因为数组没法开dp[1e + 6][1e + 6]),那可不可能把二维数组用滚动数组的方式优化成一维,但是,好想也没办法(既然一维能表示状态而且能递推,为什么要弄到二维去?)
后来我们发现我们忽略了一个条件,数据中的序列的每一项的前缀和保证大于等于0,既然这样我们就可以采用贪心的方法,sum[1, i] 保证大于等于0,加入sum[j, i]大于等于0,那么[i, j]就可以被分成一段,所以从后往前扫一遍就行了。。。

<span style="font-size:18px;">//#include<bits/stdc++.h>
#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<time.h>
#include<map>
#include<set>
using namespace std;
//#define ONLINE_JUDGE
#define eps 1e-8
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
#define INFL 0x3f3f3f3f3f3f3f3fLL
#define enter putchar(10)
#define rep(i,a,b) for(int i = (a); i < (b); ++i)
#define repe(i,a,b) for(int i = (a); i <= (b); ++i)
#define mem(a,b) (memset((a),b,sizeof(a)))
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfd(a,b) printf("%d %d\n",a,b)
#define pfP(a) printf("%d %d\n",a.fi,a.se)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%I64d\n",a)
#define ds(a) int a; sf(a)
#define PR(a,b) pair<a,b>
#define fi first
#define se second
#define LL long long
#define DB double
const double PI = acos(-1.0);
const double E = exp(1.0);
template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
template<class T> inline T Min(T a, T b) { return a < b ? a : b; }
template<class T> inline T Max(T a, T b) { return a > b ? a : b; }
int n, m;
#define N 1000010
int a
;
LL sum;

int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
//    freopen("Out.txt", "w", stdout);
#endif
while(~sf(n)) {
rep(i, 0, n) sf(a[i]);
sum = 0;
int ans = 0;
for(int i = n - 1; i >= 0; i--) {
sum += a[i];
if(sum >= 0) {
ans++;
sum = 0;
}
}
pf(ans);
}
return 0;
}</span>


well, 下一题。。

1011

http://acm.hdu.edu.cn/showproblem.php?pid=5791

Two

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 1500    Accepted Submission(s): 414


[align=left]Problem Description[/align]
Alice gets two sequences A and B. A easy problem comes. How many pair of sequence A' and sequence B' are same. For example, {1,2} and {1,2} are same. {1,2,4} and {1,4,2} are not same. A' is a subsequence
of A. B' is a subsequence of B. The subsequnce can be not continuous. For example, {1,1,2} has 7 subsequences {1},{1},{2},{1,1},{1,2},{1,2},{1,1,2}. The answer can be very large. Output the answer mod 1000000007.
 

[align=left]Input[/align]
The input contains multiple test cases.

For each test case, the first line cantains two integers
N,M(1≤N,M≤1000).
The next line contains N integers. The next line followed M integers. All integers are between 1 and 1000.
 

[align=left]Output[/align]
For each test case, output the answer mod 1000000007.
 

[align=left]Sample Input[/align]

3 2
1 2 3
2 1
3 2
1 2 3
1 2

 

[align=left]Sample Output[/align]

2
3

 题目意思是求两个序列最多有多少个顺序相同的子序列。。一道大水题。

这题不是我写的,待会上传代码

无疑是dp嘛,状态表示也很好想不过转移方程得想一下。

用dp[i][j]表示a[1 , i] 能和 b[1, j] 能形成的公共子序列个数,无疑dp[i][j] = 0 (i == 0 || j == 0)

初状态就有了,现在来考虑转移方程。

先考虑a[i] != b[j] 的情况:

    dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1];(容斥原理嘛,a[i] 和 b[j - 1]能构成的子序列个数 + a[i - 1] 和 b[j] 能构成的子序列个数 - a[i - 1] 和 b[j - 1] 能构成的子序列个数(因为在算[i, j - 1] 和 [i - 1, j]的时候重复算了一次))

那么如果a[i] == b[j] 呢?

   dp[i][j] 在a[i] != b[j] 的基础上 + dp[i - 1][j - 1] + 1;因为a[i] == b[j], a[1 , i - 1] 和 b[1, j - 1] 能形成的任何一个子序列再加上a[i](同时也是b[j])又能形成新的一个子序列(并且和原来不同,因为多了a[i]),所以能形成的新的个数自然是dp[i - 1][j - 1]个了, 并且 a[i] 自己也能形成一个仅有a[i]的序列, 所以再加上1,这样就得到了 dp[i][j] .

所以状态转移方程如下:
dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + (a[i] == b[j] ? dp[i - 1][j - 1] + 1 : 0);


这道题也很好解了:
/*************************************************************************
> File Name: 1011.cpp
> Author: Triose
> Mail: Triose@163.com
> Created Time: 2016年08月03日 星期三 13时48分21秒
************************************************************************/

//#include<bits/stdc++.h>
#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<time.h>
#include<map>
#include<set>
using namespace std;
//#define ONLINE_JUDGE
#define eps 1e-8
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
#define INFL 0x3f3f3f3f3f3f3f3fLL
#define enter putchar(10)
#define rep(i,a,b) for(int i = (a); i < (b); ++i)
#define repe(i,a,b) for(int i = (a); i <= (b); ++i)
#define mem(a,b) (memset((a),b,sizeof(a)))
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfd(a,b) printf("%d %d\n",a,b)
#define pfP(a) printf("%d %d\n",a.fi,a.se)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%I64d\n",a)
#define ds(a) int a; sf(a)
#define PR(a,b) pair<a,b>
#define fi first
#define se second
#define LL long long
#define DB double
const double PI = acos(-1.0);
const double E = exp(1.0);
template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
template<class T> inline T Min(T a, T b) { return a < b ? a : b; }
template<class T> inline T Max(T a, T b) { return a > b ? a : b; }
int n, m;
const int MOD = (1e+9) + 7;
#define N 1010
int a
, b
;
LL dp

;

void Init() {
mem(dp, 0);
repe(i, 1, n) sf(a[i]);
repe(j, 1, m) sf(b[j]);
}

void solve() {
repe(i, 1, n) {
repe(j, 1, m) {
dp[i][j] = (dp[i - 1][j] + dp[i][j - 1] - dp[i- 1][j - 1] + MOD) % MOD;
if(a[i] == b[j]) {
dp[i][j] = (dp[i][j] + dp[i - 1][j - 1] + 1) % MOD;
}
}
}
}

int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
//  freopen("Out.txt", "w", stdout);
#endif
while(~sfd(n, m)) {
Init();
solve();
pfI(dp
[m]);
}
return 0;
}


1012

http://acm.hdu.edu.cn/showproblem.php?pid=5792

World is Exploding

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 938    Accepted Submission(s): 340


[align=left]Problem Description[/align]
Given a sequence A with length n,count how many quadruple (a,b,c,d) satisfies:
a≠b≠c≠d,1≤a<b≤n,1≤c<d≤n,Aa<Ab,Ac>Ad.
 

[align=left]Input[/align]
The input consists of multiple test cases.

Each test case begin with an integer n in a single line.

The next line contains n integers A1,A2⋯An.
1≤n≤50000
0≤Ai≤1e9
 

[align=left]Output[/align]
For each test case,output a line contains an integer.
 

[align=left]Sample Input[/align]

4
2 4 1 3
4
1 2 3 4

 

[align=left]Sample Output[/align]

1
0

 
比赛的时候给了一种O(n ^ 2) 的解法(预处理 + 容斥原理)果不其然超时,超时代码就不贴了,就是统计第 i 个位置比比它大的并且在它后面的数的个数,比它大的在它前面的个数,同理统计比它小的在后面和前面的个数, 然后二重循环算一算加一加减一减就好了,超时!

再去做做再来说解法。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: