菜死了,比赛的时候T到哭
表格中
ai
代表i个a异或
m | a1 | a2 | a3 | a4 |
---|---|---|---|---|
1 | a1 | a1 ^ a2 | a1 ^ a2 ^ a3 | a1 ^ a2 ^ a3 ^ a4 |
2 | a1 | a21 ^ a2 | a31 ^ a22 ^ a3 | a41 ^ a32 ^ a23 ^ a4 |
3 | a1 | a31 ^ a2 | a61 ^ a32 ^ a3 | a101 ^ a62 ^ a33 ^ a4 |
4 | a1 | a41 ^ a2 | a101 ^ a42 ^ a3 | a201 ^ a102 ^ a43 ^ a4 |
很简单就可以找出其中系数的规律,对于异或而言,异或相同的数偶数次相当于没有异或,那么我们只需要找出其中奇数就可以了.
注意了万恶的Lucas定理:
Cmn
是奇数当且仅当把a,b二进制表达后b中1的位置是a中1的位置的子集
比赛的时候根本不知道,用Lucas求组合数,T到哭.
TLE code:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<string>
//a&3==a%4
using namespace std;
#define ll long long
#define mem(a) memset(a,0,sizeof(a))
const double eps=1e-8;
const int maxn=200010;//须填写
const int inf=0x3f3f3f3f;
const int p=1e9+7;
int a[maxn+10];
int b[maxn+10];
long long Pow(long long a,long long b)
{
long long ans=1;
while(b)
{
if(b&1)
{
b--;
ans=(ans*a)%p;
}
b>>=1;
a=(a*a)%p;
}
return ans;
}
long long C(long long n,long long m)
{
if(n<m)
return 0;
long long a=1,b=1;
while(m)
{
a=(a*n)%p;
b=(b*m)%p;
m--;
n--;
}
return (a*Pow(b,p-2))%p;
}
long long Lucas(long long n,long long m)
{
if(m==0)
return 1;
return Lucas(n/p,m/p)*C(n%p,m%p)%p;
}
bool C(int n,int b)
{
ll x=(ll)n;
ll y=(ll)b;
ll ans=Lucas(x,y);
if(ans%2==1)
return true;
else return false;
}
int main()
{
int kase;
scanf("%d",&kase);
while(kase--)
{
mem(a);
mem(b);
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",a+i);
}
for(int i=1;i<=n;i++)
{
for(int j=i;j>0;j--)
{
if(C(m-1+i-j,m-1))
{
b[i]=b[i]^a[j];
}
}
}
for(int i=1;i<n;i++)
{
printf("%d ",b[i]);
}
printf("%d\n",b[n]);
}
return 0;
}
AC code:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<string>
//a&3==a%4
using namespace std;
#define ll long long
#define mem(a) memset(a,0,sizeof(a))
const double eps=1e-8;
const int maxn=200010;//须填写
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
int a[maxn];
int b[maxn];
int main()
{
int kase;
scanf("%d",&kase);
while(kase--)
{
mem(a);
mem(b);
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",a+i);
}
for(int i=1;i<=n;i++)
{
int x=i+m-2;
int y=i-1;
if((x&y)==y)//y的1位置是x的子集则(x&y)==y
{
for(int j=i;j<=n;j++)
b[j]^=a[j-i+1];
}
}
for(int i=1;i<n;i++)
{
printf("%d ",b[i]);
}
printf("%d\n",b[n]);
}
return 0;
}