4245: [ONTAK2015]OR-XOR
Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 137 Solved: 80
[Submit][Status][Discuss]
Description
给定一个长度为n的序列a[1],a[2],...,a[n],请将它划分为m段连续的区间,设第i段的费用c[i]为该段内所有数字的异或和,则总费用为c[1] or c[2] or ... or c[m]。请求出总费用的最小值。
Input
第一行包含两个正整数n,m(1<=m<=n<=500000),分别表示序列的长度和需要划分的段数。
第一行包含n个整数,其中第i个数为a[i](0<=a[i]<=10^18)。
Output
输出一个整数,即总费用的最小值。
Sample Input
3 2
1 5 7
1 5 7
Sample Output
3
HINT
第一段为[1],第二段为[5 7],总费用为(1) or (5 xor 7) = 1 or 2 = 3。
Source
我们可以贪心的从高位向低位考虑。。。先求出前缀异或值。。对于一个二进制位如果他可以为0。。那么需要至少有m个的前缀异或值为0并且n的位置上必须为0。。然后把这个位上值为1的位置强制赋为不可取。。如果没有m个位置为0。。就把答案增加。。
#include <cstdio> #include <cstring> #include <algorithm> #define ll long long using namespace std; bool vis[500010]; ll ans=0,a[500010],n,m,cnt,f; int main(){ scanf("%lld%lld",&n,&m); for (int i=1;i<=n;i++) scanf("%lld",&a[i]),a[i]^=a[i-1]; for (int i=62;i>=0;i--){ f = 1; if ((a[n]>>i)&1) f = 0; else { cnt = 0; for (int j=1;j<n;j++) if (!vis[j] && (((a[j]>>i)&1)==0)) cnt++; if (cnt<m-1) f = 0; } if (f) {for (int j=1;j<n;j++) if ((a[j]>>i)&1) vis[j] = 1;} else ans|=(1ll<<i); } printf("%lld",ans); }
2020年2月24日 16:19
Office environment cleaning products are quite low for cost compared to the total value of using the services of conventional maintenance methods. The provider is notable mainly a result of quality for services rendered, which come up with the work place professional together with organized.