2016 Multi-University Training Contest 5
2016-08-03 13:17
330 查看
1003
http://acm.hdu.edu.cn/showproblem.php?pid=5783Divide 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=5791Two
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=5792World 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 个位置比比它大的并且在它后面的数的个数,比它大的在它前面的个数,同理统计比它小的在后面和前面的个数, 然后二重循环算一算加一加减一减就好了,超时!
再去做做再来说解法。。。
相关文章推荐
- RAID独立冗余磁盘阵列简述
- brainfack语言解析器
- hdu 5781 2016 Multi-University Training Contest 5(期望dp)
- uva 10780 Again Prime? No Time.
- Git 本地共享库无法提交 the push operation failed because no matching remote could be found
- Service和远程控制
- 《Batch Normalization Accelerating Deep Network Training by Reducing Internal Covariate Shift》阅读笔记与实现
- log4j:ERROR Failed to rename错误
- 利用正则表达式揪出网页中的email地址
- hdu 5791 Two(2016 Multi-University Training Contest 5——DP)
- hdu1848 Fibonacci again and again (博弈论sg函数模板)
- PyGobject(一百零二)Cairo系列——贪吃蛇游戏
- hdu 5791 2016 Multi-University Training Contest 5(dp)
- 编译正常后无法运行 process launch failed: failed to get the task for process 4186
- PyGobject(一百零一)Cairo系列——自定义控件
- EXPLAIN 命令
- PyGobject(一百)Cairo系列——cairo.Surface实现图片倒影
- 【POJ 3243-Clever Y】 与【POJ 2417-Discrete Logging】(解高次同余方程 Baby-Step-Gaint-Step)
- PyGobject(九十九)Cairo系列——环形加载图标
- http://blog.csdn.net/com314159/article/details/41245329