将石子从小到大排序,然后DP。
设$f[i][j][k]$表示考虑了前$i$堆的石子,当前扔掉的堆数模$d$为$j$,没有扔掉的石子的异或和为$k$的方案数。
因为石子排过序,所以转移的复杂度为$O(md)$。
对于空间的问题,注意到$f[i][j][k]$和$f[i][j][k\ xor\ a[i]]$的转移是互补的,于是可以同时处理,省去滚动数组,直接做到原地DP,当然$f[i][0][k]$要特别处理。
最后注意特判$n$是$d$的倍数的情况,此时答案应该减去$1$。
#includeconst int N=1048576,P=1000000007;int n,d,m,p,i,j,k,x,a[N],f[10][N],g[N];inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}inline int add(int a,int b){ a+=b; if(a>=P)a-=P; return a;}int main(){ for(read(n),read(d);i m)m=j; } for(f[0][0]=i=p=1;i<=m;i++){ while(p<=i)p<<=1; while(a[i]--){ for(k=0;k