即使n个数的异或为0。如果只有两堆,将质数筛出来设为1,做一个异或卷积即可。显然这个东西满足结合律,多堆时直接快速幂。可以在点值表示下进行。
#include#include #include #include #include #include using namespace std;#define N (1<<17)#define P 1000000007#define inv2 500000004int read(){ int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') { if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f;}int T,n,m,f[N];bool flag[N];int ksm(int a,int k){ int s=1; for (;k;k>>=1,a=1ll*a*a%P) if (k&1) s=1ll*s*a%P; return s;}void FWT(int *a,int n,int op){ for (int i=2;i<=n;i<<=1) for (int j=0;j >1);k++) { int x=a[k],y=a[k+(i>>1)]; a[k]=(x+y)%P,a[k+(i>>1)]=(x-y+P)%P; if (op==1) a[k]=1ll*a[k]*inv2%P,a[k+(i>>1)]=1ll*a[k+(i>>1)]*inv2%P; }}int main(){#ifndef ONLINE_JUDGE freopen("bzoj4589.in","r",stdin); freopen("bzoj4589.out","w",stdout); const char LL[]="%I64d\n";#else const char LL[]="%lld\n";#endif flag[1]=flag[0]=1; for (int i=2;i<=50000;i++) for (int j=2;j<=50000/i;j++) flag[i*j]=1; while (scanf("%d %d",&n,&m)!=EOF) { int t=1;while (t<=m) t<<=1; for (int i=0;i<=m;i++) f[i]=flag[i]^1; for (int i=m+1;i