bzoj 4245: [ONTAK2015]OR-XOR
2018-03-09 11:58
330 查看
题意:
给定一个长度为n的序列a[1],a[2],…,a,请将它划分为m段连续的区间,设第i段的费用c[i]为该段内所有数字的异或和,则总费用为c[1] or c[2] or … or c[m]。请求出总费用的最小值。
题解:
一开始列错式子了,浪费很多时间,一定要检查最初的式子。先变为前缀和形式sumsum
ans=sr1|(sr1 xor sr2)|(sr2 xor sr3)|……|(srm−1 xor sn)ans=sr1|(sr1 xor sr2)|(sr2 xor sr3)|……|(srm−1 xor sn)
显然有a xor b|b=a|ba xor b|b=a|b
所以上式就是:ans=sr1|sr1|sr2|……|srm−1|snans=sr1|sr1|sr2|……|srm−1|sn
就变成了选m-1个数,与snsn或的最大值。
高位到低位贪心即可。
code:
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #define LL long long using namespace std; int n,m; LL a[500010],ans=0; bool check[500010]; LL read() { LL x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int solve(int k) { int num=0; for(int i=1;i<n;i++) if(check[i]) num+=(a[i]&(1LL<<k))?0:1; return num; } void change(int k) { for(int i=1;i<n;i++) if(a[i]&(1LL<<k)) check[i]=false; } int main() { scanf("%d %d",&n,&m);m--; for(int i=1;i<=n;i++) a[i]=read(),a[i]^=a[i-1]; memset(check,true,sizeof(check)); for(int k=59;k>=0;k--) { if((1LL<<k)&a ) ans=(ans<<1)+1; else { int t=solve(k); if(t<m) ans=(ans<<1)+1; else ans<<=1,change(k); } } printf("%lld",ans); }
相关文章推荐
- 【ONTAK2015】【BZOJ4245】OR-XOR
- BZOJ4245 [ONTAK2015]OR-XOR
- 【BZOJ 4245】[ONTAK2015]OR-XOR 二进制贪心
- BZOJ 4245 [ONTAK2015]OR-XOR 贪心 思维
- BZOJ4245 ONTAK2015 OR-XOR(贪心)
- 【bzoj4245】【ONTAK2015】OR-XOR(位运算)
- bzoj4245 [ONTAK2015]OR-XOR
- [BZOJ4245][ONTAK2015]OR-XOR(贪心)
- 【BZOJ4245】【ONTAK2015】OR-XOR
- [乱搞] BZOJ 4245 [ONTAK2015]OR-XOR
- BZOJ 4245: [ONTAK2015]OR-XOR|进制类|贪心
- BZOJ 4245: [ONTAK2015]OR-XOR 贪心
- 【bzoj4245】[ONTAK2015]OR-XOR 贪心
- 【BZOJ】4245: [ONTAK2015]OR-XOR
- BZOJ 4245: [ONTAK2015]OR-XOR
- [bzoj4245][ONTAK2015]OR-XOR
- BZOJ4245 [ONTAK2015]OR-XOR 【贪心】
- 【bzoj4245】[ONTAK2015]OR-XOR 按位拆分+贪心
- 【bzoj4245】[ONTAK2015]OR-XOR
- 【BZOJ4245】[ONTAK2015]OR-XOR 贪心