[loj#2409][THUPC2017]sum
ofollow,noindex" target="_blank">題目傳送門
這題比較變態(可能是因為我太菜了),是那位金牌爺講的倒數第二題(最後一題是那位金牌爺在考場上沒做出來的題,此題過於變態暫時我們都不想做了)。
此題已知有兩種做法,按該金牌爺的做法會被卡常,本人常數優化了一個下午才過。
這題看得我一臉懵逼,這位金牌爺做法的腦洞真的有點大,智商完全碾壓我們,我覺得如果我自己想可能真的想不出來…..
我們把問題轉化為多項式,則我們要求的是:
\sum_{i=0}^{n}(\sum_{j=1}^{n}a_j^i)x^i
不妨令其變為:
\sum_{i=0}^{n}(\sum_{j=1}^{n}a_j^i)x^i\%x^{n+1}
考慮式子:
\sum_{i=0}^{n}x^i=\frac{1-x^{n+1}}{1-x}\equiv \frac{1}{1-x}(mod x^{n+1})
那麼原式可以化為:
\sum_{i=0}^n\frac{1}{1-ax}\%x^{n+1}
該式我們可以使用分治NTT+多項式求逆來求解答案。
由於分治需要維護的是分數,所以每一次合併要用6次NTT,效率比較低下(另一種做法也是需要分治NTT的,但是合併只需要三次NTT)。
巫蠱偶大神常數優秀,碼完就AC,真的強。本人卡了半天常數,還對著巫蠱偶大佬的程式碼學習卡常技巧,最後終於過了。。。。
\#include<cstdio> #include<algorithm> using namespace std; const int MAX_N=1<<19|5; const int MOD=998244353; int a[MAX_N],b[MAX_N],a1[MAX_N],b1[MAX_N],a2[MAX_N],b2[MAX_N]; int w[MAX_N],inv[MAX_N],g[MAX_N]; inline int fast_pow(int x,int n){ int ret=1; for(;n;n>>=1,x=1ll*x*x%MOD) if(n&1) ret=1ll*ret*x%MOD; return ret; } void NTT(int a[],int n){ for(int i=0,pos=0;i<n;++i){ if(i<pos) swap(a[i],a[pos]); for(int p=n>>1;(pos^=p)<p;p>>=1); } static int p[MAX_N]; p[0]=1; for(register int step=1;step<n;step<<=1){ register int wn=w[step],stepx=step<<1; for(register int i=1;i<step;++i) p[i]=1ll*p[i-1]*wn%MOD; for(register int i=0;i<n;i+=stepx) for(register int j=i;j<i+step;++j){ register int x=a[j],y=1ll*a[j+step]*p[j-i]%MOD; a[j]=x+y>=MOD?x+y-MOD:x+y; a[j+step]=x-y<0?x-y+MOD:x-y; } } } void get_inv(int a[],int b[],int n){ b[0]=fast_pow(a[0],MOD-2); for(int sz=2;sz<=n;sz<<=1){ int len=sz<<1; for(int i=sz>>1;i<len;++i) b[i]=0; for(int i=0;i<sz;++i) g[i]=a[i],g[i+sz]=0; NTT(g,len); NTT(b,len); for(int i=0;i<len;++i) b[i]=(2ll+MOD-1ll*g[i]*b[i]%MOD)*b[i]%MOD; reverse(b+1,b+len); NTT(b,len); int invn=inv[len]; for(int i=0;i<sz;++i) b[i]=1ll*b[i]*invn%MOD; } } void dc(int n){ for(int sz=2;sz<n;sz<<=1) for(int l=0;l<n;l+=sz<<1){ int len=sz<<1,m=l+sz; for(int i=0;i<sz;++i){ a1[i]=a[l+i]; a1[i+sz]=0; b1[i]=b[l+i]; b1[i+sz]=0; a2[i]=a[m+i]; a2[i+sz]=0; b2[i]=b[m+i]; b2[i+sz]=0; } NTT(a1,len); NTT(b1,len); NTT(a2,len); NTT(b2,len); for(int i=0;i<len;++i){ a[i+l]=(1ll*a1[i]*b2[i]+1ll*a2[i]*b1[i])%MOD; b[i+l]=1ll*b1[i]*b2[i]%MOD; } reverse(a+l+1,a+l+len); reverse(b+l+1,b+l+len); NTT(a+l,len); NTT(b+l,len); int invn=inv[len]; for(int i=0;i<len;++i){ a[i+l]=1ll*a[i+l]*invn%MOD; b[i+l]=1ll*b[i+l]*invn%MOD; } } } inline int getint(){ register int ret=0; register char c=getchar(); for(;c<'0'||c>'9';c=getchar()); for(;c>='0'&&c<='9';c=getchar()) ret=(ret<<3)+(ret<<1)+c-'0'; return ret%MOD; } int main(){ for(int i=0;i<=19;++i) inv[1<<i]=fast_pow(1<<i,MOD-2); for(int i=0;i<=18;++i) w[1<<i]=fast_pow(3,(MOD-1)/(1<<i+1)); int T=getint(); while(T--){ int n=getint(),top; for(top=1;top<=n+n+1;top<<=1); for(int i=0;i<top;++i) b[i]=~i&1,a[i]=0; for(int i=0;i<n;++i) b[i+i+1]=MOD-getint(),a[i+i]=1; dc(top); int len=top>>1; get_inv(b,b1,len); for(int i=len;i<top;++i) b1[i]=0; NTT(a,top); NTT(b1,top); for(int i=0;i<top;++i) a[i]=1ll*a[i]*b1[i]%MOD; reverse(a+1,a+top); NTT(a,top); for(int i=0;i<top;++i) a[i]=1ll*a[i]*inv[top]%MOD; int ans=0; for(int i=1;i<=n;++i) ans^=a[i]; printf("%d\n",ans); } return 0; }