商城建设开发/seo专员很难吗
题目
正解
随便生成函数,显然答案为(∏(1+xti))m(\prod (1+x^{t_i}))^m(∏(1+xti))m
外面的这个乘方可以直接快速幂,时间复杂度O(elgelgm)O(e\lg e \lg m)O(elgelgm)。
重点是如何计算里面的这个东西。
由于∑ti≤2e7\sum t_i\leq2e7∑ti≤2e7,所以不同的tititi的个数大概是∑ti\sqrt {\sum t_i}∑ti,约等于600060006000。
将tit_iti相同的一起计算,用个组合数就可以做到O(个数)O(个数)O(个数)处理,然后花O(∑tielge)O(\sqrt {\sum t_i}e\lg e)O(∑tielge)的时间来将tit_iti不同的合并起来。
然而常数太大TLE了……
这时候可以想到当个数比较少的时候,直接暴力做。
定义一个阈值,理论上这个阈值设lge\lg elge最优,实际上这只有85分。
跑个大数据,然后手动三分一下阈值,发现当这个阈值设为100010001000的时候跑得最快。
于是就过了……
当然上面那样做是水法。
正解是一个见过一次就可能不会忘的小科技。
考虑这题本质上就是做一个长度为eee的循环卷积。题目给出的xxx显然就是eee次单位根(xe≡(modp)x^e\equiv \pmod pxe≡(modp))。
如果我们求出了长度为eee的DFTDFTDFT,在这个DFTDFTDFT上操作一波之后再IDFTIDFTIDFT回去,那就可以达到一个优秀的时间复杂度。
现在的问题是如何求这个东西:(注意我们平常求的DFTDFTDFT要将长度凑到2k2^k2k形式的,这样算的循环卷积就是2k2^k2k长度的循环卷积,和我们要求的不同)
记单位根为ωe\omega_eωe(就是题目的xxx),我们要求F(ωek)F(\omega_e^k)F(ωek),其中k∈[0,e)k\in [0,e)k∈[0,e)
F(ωek)=∑i=0e−1aiωik=∑i=0e−1aiωek2+i2−(k−i)22=∑i=0e−1aiω2ek2+i2−(k−i)2=ω2ek2∑i=0e−1aiω2ei2ω2e−(k−i)2F(\omega_e^k)=\sum_{i=0}^{e-1}a_i\omega^{ik} \\ =\sum_{i=0}^{e-1} a_i\omega_e^{\frac{k^2+i^2-(k-i)^2}{2}} \\ =\sum_{i=0}^{e-1} a_i\omega_{2e}^{k^2+i^2-(k-i)^2} \\ =\omega_{2e}^{k^2}\sum_{i=0}^{e-1} a_i\omega_{2e}^{i^2}\omega_{2e}^{-(k-i)^2}F(ωek)=i=0∑e−1aiωik=i=0∑e−1aiωe2k2+i2−(k−i)2=i=0∑e−1aiω2ek2+i2−(k−i)2=ω2ek2i=0∑e−1aiω2ei2ω2e−(k−i)2
后面的显然是个卷积,于是NTT即可(这个NTT和我们这里说了求长度为eee的DFT没有什么关系,不要混淆……)
不过有时候ωe\omega_eωe没有平方根,那么还有另一种拆分方式:
F(ωek)=∑i=0e−1aiωik=∑i=0e−1aiωeCk+i2−Ck2−Ci2F(\omega_e^k)=\sum_{i=0}^{e-1}a_i\omega^{ik} \\ =\sum_{i=0}^{e-1} a_i\omega_e^{C_{k+i}^2-C_k^2-C_i^2}F(ωek)=i=0∑e−1aiωik=i=0∑e−1aiωeCk+i2−Ck2−Ci2
同样可以求得。
至于IDFTIDFTIDFT,用ω−1\omega^{-1}ω−1代进去,最终结果乘e−1e^{-1}e−1即可。
对于这题,直接套用这个做法可以得到和暴力差不多的时间(除快速幂部分外,快速幂部分直接在点值上快速幂)。
这题有个更简单的实现方式:对于一个1+xti1+x^{t_i}1+xti,直接将ωek,k∈[0,e)\omega_e^k,k\in[0,e)ωek,k∈[0,e)代进去,就可以快速地计算出它的DFTDFTDFT。然后它的乘方就直接在点值上乘方,接着将tit_iti不同的按对应的位置乘在一起,再把每个位置取mmm次方,最后IDFTIDFTIDFT回来。
于是真正需要实现上面这个算法的部分就只有一次IDFTIDFTIDFT啊……
代码
水法
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 1000010
#define mo 998244353
#define E 131072
#define T 20000000
#define ll long long
ll qpow(ll x,int y=mo-2){ll r=1;for (;y;y>>=1,x=x*x%mo)if (y&1)r=r*x%mo;return r;
}
int n,m,x,e;
int t[N];
int nN,re[E],w[E];
void setlen(int n){int bit=0;for (nN=1;nN<=n;nN<<=1,bit++);re[0]=0;for (int i=1;i<nN;++i)re[i]=re[i>>1]>>1|(i&1)<<bit-1;
}
void clear(ll A[],int n){memset(A,0,sizeof(ll)*n);
}
void dft(ll A[],int flag){for (int i=0;i<nN;++i)if (i<re[i])swap(A[i],A[re[i]]);for (int i=1;i<nN;i<<=1){ll wn=qpow(3,(flag==1?(mo-1)/(2*i):mo-1-(mo-1)/(2*i)));w[0]=1;for (int k=1;k<i;++k)w[k]=(ll)w[k-1]*wn%mo;for (int j=0;j<nN;j+=i<<1)for (int k=0;k<i;++k){ll x=A[j+k],y=w[k]*A[j+k+i];A[j+k]=(x+y)%mo;A[j+k+i]=(x-y+(ll)mo*mo)%mo;}}if (flag==-1){ll invn=qpow(nN);for (int i=0;i<nN;++i)A[i]=A[i]*invn%mo;}
}
void multi(ll c[],ll a[],ll b[],int n){static ll A[E],B[E];setlen(n*2);clear(A,nN);for (int i=0;i<n;++i)A[i]=a[i];dft(A,1);if (a!=b){clear(B,nN);for (int i=0;i<n;++i)B[i]=b[i];dft(B,1);for (int i=0;i<nN;++i)c[i]=A[i]*B[i]%mo;}else{for (int i=0;i<nN;++i)c[i]=A[i]*A[i]%mo;}dft(c,-1);for (int i=n;i<nN;++i){(c[i-n]+=c[i])%=mo;c[i]=0;}
}
ll fac[N],ifac[N];
ll C(int m,int n){return fac[m]*ifac[n]%mo*ifac[m-n]%mo;}
ll F[E],G[E],H[E];
struct Ans{int a,b;
} ans[N];
int cnt;
bool cmpa(Ans x,Ans y){return x.a<y.a;}
int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);freopen("number.in","r",stdin);freopen("number.out","w",stdout);scanf("%d%d%d",&n,&m,&x);for (int i=1,pw=x;i<=50000;++i,pw=(ll)pw*x%mo)if (pw==1){e=i;break;}fac[0]=1;for (int i=1;i<=n;++i)fac[i]=fac[i-1]*i%mo;ifac[n]=qpow(fac[n]);for (int i=n-1;i>=0;--i)ifac[i]=ifac[i+1]*(i+1)%mo; for (int i=1;i<=n;++i)scanf("%d",&t[i]);sort(t+1,t+n+1);H[0]=1;int B=/*log2(e)*/1000;for (int i=1,j=1;i<=n;++i)if (t[i]!=t[i+1]){int l=i-j+1;if (l>B){for (int k=0;k<=l;++k)F[(ll)k*t[i]%e]+=C(l,k);multi(H,H,F,e);for (int k=0;k<=l;++k)F[(ll)k*t[i]%e]=0;}else{while (l--){for (int k=e-1;k>=0;--k)(H[k+t[i]]+=H[k])%=mo;for (int k=e-1+t[i];k>=e;--k)(H[k-e]+=H[k])%=mo,H[k]=0;}}j=i+1;}G[0]=1;for (;m;m>>=1,multi(H,H,H,e))if (m&1)multi(G,G,H,e);for (int i=0,pw=1;i<e;++i,pw=(ll)pw*x%mo){int a=pw,b=G[i];if (b)ans[++cnt]={a,b};}sort(ans+1,ans+cnt+1,cmpa);for (int i=1;i<=cnt;++i)printf("%d %d\n",ans[i].a,ans[i].b);return 0;
}