AtCoder Grand Contest 043B(组合数学)
先进行一次绝对值差分,把序列中的数都变成 0,1,2 。如果序列中存在 1,答案只能是 0 或 1;如果不存在 1,答案只能是 0 或 2。对于不存在 1 的情况,我们可以将每个数都 除以2,最后再将答案 乘2,这显然是等价的。于是现在答案只能是 0 或 1 ,发现绝对值差分等价于异或。现在问题转化为一个 只包含0和1的序列,每次将相邻两个数异或,求最后剩下的数。那么考虑每个数会被异或几次即可,设序列长度为 n,则位置 i 上的数会被异或 (n−1,i−1) 次。这时候我们还要求出模 2 意义下的组合数,一个简单的方法是计算每个阶乘的分解中 2 的次数,将计算组合数时的除法改为做减法。则对于一个组合数,最后如果剩下的 2 的次数为 0,则说明 mod2=1,否则 mod2=0。对于阶乘的分解,可以先对每个数简单地求出分解中 2 的次数,然后做前缀和即可。时间复杂度 O(n)。
1 #define HAVE_STRUCT_TIMESPEC 2 #include<bits/stdc++.h> 3 using namespace std; 4 int a[1000007],c[1000007]; 5 char s[1000007]; 6 int main() { 7 ios::sync_with_stdio(false); 8 cin.tie(NULL); 9 cout.tie(NULL); 10 int n; 11 cin>>n; 12 cin>>s+1; 13 --n; 14 for(int i=1;i<=n;++i) 15 a[i]=abs(s[i]-s[i+1]); 16 int flag=0; 17 for(int i=1;i<=n;++i) 18 if(a[i]==1) 19 flag=1; 20 if(!flag) 21 for(int i=1;i<=n;++i) 22 a[i]>>=1; 23 for(int i=1;i<=n;++i){ 24 int x=i; 25 while(!(x&1)) 26 ++c[i],x>>=1; 27 c[i]+=c[i-1]; 28 } 29 int ans=0; 30 for(int i=1;i<=n;++i) 31 ans^=c[n-1]-c[i-1]-c[n-i]?0:(a[i]&1); 32 if(!flag) 33 ans<<=1; 34 cout<<ans; 35 return 0; 36 }
保持热爱 不懈努力
不试试看怎么知道会失败呢(划掉)
世上无难事 只要肯放弃(划掉)