codeforces 811C C. Vladik and Memorable Trip

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/My_stage/article/details/77665143

http://codeforces.com/problemset/problem/811/C

题意:
给一个长度为n的序列,你从中选取若干个区间(不能重叠),并且每个区间内的数只能出现在这个区间里 如 1 2 2 1 你可以选【2,3】,[1,4],不可以选 [1,2],[1,3],[2,4]; 每个区间的权为区间内去重后的异或和,之后区间加和,求最大。

思路:用DP求解,预处理出每个数第一次出现的位置和最后一次出现的位置。之后处理处[i]~[j]的区间异或和,之后我们维护下每个可能的区间和最大即可。

#include <bits/stdc++.h>
#define maxs 2020202
#define ll long long
#define inf LONG_LONG_MAX
#define mme(i,j) memset(i,j,sizeof(i))
using namespace std;
ll dp[5005],a[maxs];
ll n;
int st[maxs],ed[maxs];
bool vis[5005];
ll val[5005][5005];

int main()
{
    while(~scanf("%lld",&n))
    {
        for(int i=1; i<=n; i++)
            scanf("%lld",&a[i]);
        mme(dp,0);
        mme(st,0);
        mme(ed,0);
        mme(val,0);
        for(int i=1; i<=n; i++)
        {
            if(st[a[i]])
                st[a[i]] = min(i,st[a[i]]);
            else
                st[a[i]]=i;
            if(ed[ a[i] ])
                ed[ a[i] ] = max(i,ed[ a[i] ]);
            else
                ed[ a[i] ] =i;
        }
        for(int i=1; i<=n; i++)
        {
            mme(vis,0);
            val[i][i]=a[i];
            vis[ a[i] ] =1;
            for(int j=i+1; j<=n; j++)
            {
                if(!vis[ a[j] ])
                {
                    val[i][j] =val[i][j-1]^a[j];
                    vis[ a[j] ] =1;
                }
                else
                    val[i][j] = val[i][j-1];
            }
        }
        int tp,ok=1;
        for(int i=1; i<=n; i++)
        {
            if(i == ed[a[i]])
            {
                tp = a[i];
                ok=1;
                int left = st[tp];
                for(int j = st[tp]+1; j<ed[tp]; j++)
                {
                    if(ed[ a[j] ] >i)
                    {
                        ok=0;
                        break;
                    }
                    left = min(left,st[ a[j] ]);
                }
                if(ok)
                    dp[i]=max(dp[i-1],dp[left-1]+val[left][i]);
                else
                    dp[i] = dp[i-1];
            }
            else dp[i]=dp[i-1];
        }
        printf("%lld\n",dp[n]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/My_stage/article/details/77665143
今日推荐