牛客练习赛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); }