srm 524 div1
2012-05-18 03:10 macaroniz 阅读(239) 评论(0) 收藏 举报250pt
很水的题不写了
500pt
有这几个重要的观察:
1、如果存在长度为len的序列,那么必定存在长度为len-1的序列,这一点让我们可以将求解过程转化为二分答案+判定的过程。
2、如果将子段和表示成Sum差(sum[i]-sum[j],sum表示a[0]~a[i]的元素和)的形式,实际上就是一个判断是否存在自环的问题。
3、答案不超过1000^2,实际上官方题解上给出了一个更优的下界——答案不超过minx{|C[i]| + |C[j]| - 1},其中要求C[i]与C[j]符号不同,这个结果实际上是构造得到的:
不妨设C[i] > 0,C[j]<0,且|C[i]| > |C[j]|
那么我们可以将子序列和依次写出来:
a1+a2+a3+...+a|c[j]|
a2+a3+a4+...+a|c[j]|+1
.....
a|c[i]| + a|c[i]+1|+....+a{|c[i]| +|c[j]|-1}
注意到这个矩阵的每一行之和都是负的,每一列之和都是正的,而这明显是矛盾的,因此答案不会超过minx{|C[i]| + |C[j]| - 1}
到了这里实际上已经可以做了。不过官方题解还给出了一个观察,petr教主在程序中也使用了这个性质:
4、如果该图包含环,那么顶点0一定在某个环中,官方的证明很结论化,我也不会严格的证明,但是直观上很好理解,详细的证明请移步官网。
class LongestSequence { public: bool vis[2010]; void dfs(int x,int len,const vector<int> &C) { for(int i = 0;i < C.size();i++) { int z = x + C[i]; if(0<=z && z<=len && vis[z] == 0) { vis[z] = 1; dfs(z,len,C); } } } int maxLength(vector <int> C) { int ne = 0,po = 0; for(int i = 0;i < C.size();i++) { if(C[i] < 0) ne++; else po++; } if(po == 0 || ne == 0) return -1; int l = 0,r = 2000; while(l < r) { int mid = (l + r + 1)/2; memset(vis,0,sizeof vis); dfs(0,mid,C); if(vis[0] == 0) l = mid; else r = mid - 1; } return l; } };
1000pt
浙公网安备 33010602011771号