牛客练习赛78 E CCA的区间

https://ac.nowcoder.com/acm/contest/11168/E

 

如果没有区间翻转操作

那就直接枚举区间左或右端点,

因为要求数不能重复,每个数字又都是2的幂

所以固定一个端点后,区间长度是log(值域)级别的,这里就是24

 

可以翻转一个区间,相当于可以选任意2个不相交的区间

这里的不相交指的是位置不相交

由于2个区间无重复数字一定能得出2个区间位置不相交

而有重复数字且区间不相交是不合法的情况

所以相当于选2个无重复(区间内和区间之间)数字的区间

这可以用状压dp求解

 

按照最开始说的可以先求出dp[i]=i,表示有一个无重复数字区间,它的数字和为i

然后求出dp[i]=x,表示状态i的子集里最大的数字和

可以通过从小到大枚举所有状态i,逐次去掉i的一个2的幂次求

最后求所有的max(dp[i]+dp[总状态 ^ i])

 

#include<cstdio>
#include<algorithm> 

using namespace std;

#define N 100001

int a[N],dp[1<<24];

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;++i) scanf("%d",&a[i]);
    int s;
    for(int i=1;i<=n;++i)
    {
        s=0;
        for(int j=i;j;--j)
        {
            if(a[j]&s) break;
            s|=a[j];
            dp[s]=s;
        }
    }
    s=(1<<24)-1;
    for(int i=1;i<=s;++i)
        for(int j=0;j<=23;++j)
            if(i&1<<j) dp[i]=max(dp[i],dp[i^1<<j]);
    int ans=0;
    for(int i=1;i<=s;++i) ans=max(ans,dp[i]+dp[s^i]);
    printf("%d",ans);
}

 

posted @ 2021-03-15 14:09  TRTTG  阅读(146)  评论(0编辑  收藏  举报