考虑没有任何限制的东西,

m个元素分为n个连续的区间,直接用组合数插板法就好了。

考虑如何去掉元素大于$a_i$的限制,

只要给最终的元素个数减掉$a_i$就好了。

考虑如何搞元素个数小于$a_i$的限制,

不妨使用子集反演,要求的是恰好$0$个元素大于$a_i$。

只要钦定其中的每个集合元素大于$a_i$,问题就转化为了容易解决的问题,乘上容斥系数就好了。

因为模数满足$p^k$并不大,使用$exlucas$(实际上就是不断提取$p$这个质因子)就好了。

 

B. 宇宙序列

因为异或的性质$a\ xor\ b\ xor\ b=a$,题中给出的式子可以转化为异或卷积式。

因为异或卷积具有结合律,可以直接倍增求,使用FWT优化,可以做到$O(pn2^n)$。

通过DFT,可以将异或的卷积式转化为对位相乘。

暴力相加并不容易优化,但是可以发现对位相乘的结果的形式是优美的。

根据异或FWT的DFT性质(可以结合或卷积的子集和理解),可以发现不断在系数/点值两种情况下转换是没有意义的。

只要在点值意义下不断的自乘,累加在另一个数组中就可以了。

设$a$数组DFT之后为$A$数组,那么对于$A_i$,对应的累加结果为$B_i=\sum \limits_{j=0}^{p}A_i^{2^j}$。

问题在于求出$B$,一次性IDFT回去就好了。

利用本题中模数并不大($10007$)的性质,找一下循环节可以做到$O(mod^2)$预处理。

然而正解是一个倍增。

设$f_{x,k}=\sum \limits_{j=0}^{2^k-1}x^{2^j}$

有$f_{x,k}=f_{x,k-1}+f_{x^{2^{2^{k-1}}},k-1}$

询问的时候只要用类似的方法倍增统计就好了。

用一些特殊的技巧,可以将总复杂度做到$O(mod*logp+n*2^n)$。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int mod=10007;
 4 const int inv2=5004;
 5 const int N=262150;
 6 int n,p,d,lim;
 7 int a[N],f[mod][32];
 8 inline void fwt(int opt){
 9     for(int i=1;i<lim;i<<=1)
10         for(int j=0;j<lim;j+=i<<1)
11             for(int k=0;k<i;++k){
12                 int x=a[j+k],y=a[j+k+i];
13                 a[j+k]=(x+y)%mod; a[j+k+i]=(x-y+mod)%mod;
14                 if(opt==-1) a[j+k]=a[j+k]*inv2%mod,a[j+k+i]=a[j+k+i]*inv2%mod;
15             }
16 }
17 inline int qpow(int x,int k,int mod,int r=1){
18     for(;k;k>>=1,x=x*x%mod) if(k&1) r=r*x%mod;
19     return r;
20 }
21 inline int query(int x,int k,int ans=0,int r=0){
22     for(int i=0;i<30;++i) if(k>>i&1) ans+=f[qpow(x,qpow(2,r%5002,mod-1),mod)][i],r+=1<<i;
23     return ans%mod;
24 }
25 inline int read(register int x=0,register char ch=getchar(),register int f=0){
26     for(;!isdigit(ch);ch=getchar()) f=ch=='-';
27     for(; isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
28     return f?-x:x;
29 }
30 int main(){
31     n=read(); p=read(); d=read(); lim=1<<n;
32     for(int i=0;i<lim;++i) a[i]=read();
33     for(int i=0;i<mod;++i) f[i][0]=i;
34     for(int i=1;i<30;++i) for(int j=0;j<mod;++j) f[j][i]=(f[j][i-1]+f[qpow(j,qpow(2,(1<<i-1)%5002,mod-1),mod)][i-1])%mod;
35     fwt(1);
36     for(int j=0;j<lim;++j) a[j]=query(a[j],p+1);
37     fwt(-1);
38     printf("%d\n",a[d]);
39     return 0;
40 }
T2

相关文章:

  • 2021-07-21
  • 2021-08-07
  • 2022-12-23
  • 2021-04-10
  • 2022-12-23
  • 2021-06-25
  • 2022-01-12
  • 2021-06-04
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2021-07-30
  • 2022-02-05
  • 2021-10-24
  • 2021-07-31
  • 2021-09-25
相关资源
相似解决方案