代码改变世界

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