您的位置:首页 > 其它

【GDKOI2017模拟1.12】与运算

2017-01-16 21:59 141 查看

Description

给出一个序列,Fi为前i项进行and运算之后的值。求这个序列的一个排列,使得∑Fi最大。

输出这个最大值。

n<=10^6

Solution

首先考虑F数组,显然是单调不升的。

那么我们考虑Dp,Dp i表示F数组目前最后一位为i的最大和。注意可以不放满。

那么我们枚举一个数转移,复杂度是O(N^2)的。

转移的话我们可以预处理cnt[i]表示有多少个数and i等于i的。

这个东西可以用经典分治求出来,把二进制每一位分成0和1,把1的答案加到0上。

然后转移就显然了。

然后我们发现如果我们把转移看做很多次减去一个2的幂,那么每一次我们只需要把i的二进制减去一个1就好了。

每次转移可以拆成很多次转移嘛~

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int N=1.5*1e6+5,D=20;
int cnt
,mi[D+5],n,x;
ll f
,ans;
void solve(int l,int r) {
if (l==r) return;
int mid=(l+r)/2;
solve(l,mid);solve(mid+1,r);
fo(i,mid+1,r) cnt[i-mid+l-1]+=cnt[i];
}
int main() {
freopen("and.in","r",stdin);
freopen("and.out","w",stdout);
scanf("%d",&n);
fo(i,1,n) scanf("%d",&x),cnt[x]++;
mi[0]=1;
fo(i,1,D) mi[i]=mi[i-1]*2;
solve(0,mi[D]-1);
f[mi[D]-1]=cnt[mi[D]-1]*(mi[D]-1);
fd(i,mi[D]-1,0) {
fo(j,0,D) if (i&mi[j]) {
x=i-mi[j];
f[x]=max(f[x],f[i]+(ll)x*(cnt[x]-cnt[i]));
}
ans=max(ans,f[i]);
}
printf("%lld\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: