傳送門
文章目錄
題意:
求aaa的所有子序列的和的乘積。
思路:
看到suma≤1e5sum_a\le1e5suma?≤1e5,這應該會給我們提示,但是我沒看到。
我們可以記cntxcnt_xcntx?表示和為xxx的子序列有cntxcnt_xcntx?個,那么答案就是∏xcntx\prod x^{cnt_x}∏xcntx?。
考慮求cntxcnt_xcntx?,我們定義f[i][j]f[i][j]f[i][j]表示前iii個數和為jjj的數有多少,顯然可以n2n^2n2轉移。
考慮這是一個經典問題,將每一項aia_iai?寫成多項式1+xai1+x^{a_i}1+xai?,那么nnn個多項式乘起來之后,指數為xxx,系數為cntxcnt_xcntx?,但是這個過程仍然是n2n^2n2的。
由于我們將其轉換成多項式了,而多項式相乘是無序的,所以可以用分治來優化這個過程,每層用FFTFFTFFT來計算即可。又因為要取模,所以可以用三模NTTNTTNTT或者拆系數FFTFFTFFT,這里采用FFTFFTFFT即可。注意這里多項式的取模應該是mod?1mod-1mod?1,因為其實際是指數,我們要用費馬小定理降冪。
在就是實現的時候一些小技巧了,比如我們需要返回一個多項式,直接返回肯定炸掉了,我們可以返回一個指針,就可以完美的返回一個多項式了。
最后直接算一下答案即可。
#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#include<random>
#include<cassert>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid ((tr[u].l+tr[u].r)>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std
;
typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<int,int> PII
;const int N
=1000010,mod
=998244353,INF
=0x3f3f3f3f,P
=1<<15;
const double eps
=1e-6;int n
,m
;
int a
[N
];struct MTT {long double PI
=acos(-1);int rev
[N
];int bit
,limit
;struct Complex {long double x
,y
;void init() { x
=y
=0; }Complex
operator + (const Complex
& t
) const { return {x
+t
.x
,y
+t
.y
}; }Complex
operator - (const Complex
& t
) const { return {x
-t
.x
,y
-t
.y
}; }Complex
operator * (const Complex
& t
) const { return {x
*t
.x
-y
*t
.y
,x
*t
.y
+y
*t
.x
}; } }p1
[N
],p2
[N
],g
[N
];void init(int n
,int m
) {int x
=n
+m
; bit
=0;while((1<<bit
)<=x
) bit
++;limit
=1<<bit
;for(int i
=0;i
<limit
;i
++) rev
[i
]=(rev
[i
>>1]>>1)|((i
&1)<<(bit
-1));}void fft(Complex a
[],int inv
) {for(int i
=0;i
<limit
;i
++) if(i
<rev
[i
]) swap(a
[i
],a
[rev
[i
]]);for(int mid
=1;mid
<limit
;mid
<<=1) {Complex w1
=Complex({cos(PI
/mid
),inv
*sin(PI
/mid
)});for(int i
=0;i
<limit
;i
+=mid
*2) {Complex wk
=Complex({1,0});for(int j
=0;j
<mid
;j
++,wk
=wk
*w1
) {Complex x
=a
[i
+j
],y
=wk
*a
[i
+j
+mid
];a
[i
+j
]=x
+y
; a
[i
+j
+mid
]=x
-y
;}}}}int mul(int *as
,int *a
,int n
,int *b
,int m
,int mod
) {for(int i
=0;i
<n
;i
++) {int x
=a
[i
];int aa
=x
>>15,bb
=x
&0x7fff;p1
[i
]={(long double)aa
,(long double)bb
};p2
[i
]={(long double)aa
,-(long double)bb
};}for(int i
=0;i
<m
;i
++) {int x
=b
[i
];int aa
=x
>>15,bb
=x
&0x7fff;g
[i
]={(long double)aa
,(long double)bb
};}init(n
,m
);fft(p1
,1); fft(p2
,1); fft(g
,1);for(int i
=0;i
<limit
;i
++) g
[i
].x
/=limit
,g
[i
].y
/=limit
;for(int i
=0;i
<limit
;i
++) p1
[i
]=p1
[i
]*g
[i
],p2
[i
]=p2
[i
]*g
[i
];fft(p1
,-1); fft(p2
,-1);for(int i
=0;i
<=m
+n
;i
++) {LL ans
=0,a1b1
=0,a2b2
=0,a1b2
=0,a2b1
=0;a1b1
=(long long)floor((p1
[i
].x
+p2
[i
].x
)/2+0.49)%mod
;a1b2
=(long long)floor((p1
[i
].y
+p2
[i
].y
)/2+0.49)%mod
;a2b1
=((long long)floor(p1
[i
].y
+0.49)-a1b2
)%mod
;a2b2
=((long long)floor(p2
[i
].x
+0.49)-a1b1
)%mod
;ans
=(((((a1b1
<<15)%mod
+(a1b2
+a2b1
))%mod
)<<15)%mod
+a2b2
)%mod
;ans
+=mod
; ans
%=mod
;as
[i
]=ans
;}for(int i
=0;i
<limit
;i
++) p1
[i
].init(),p2
[i
].init(),g
[i
].init();return n
+m
;}
}MT
;int all
,al
[N
*4];struct Com {int *a
,len
;void init(int l
) {a
=al
+all
; len
=l
; all
+=l
;for(int i
=0;i
<len
;i
++) a
[i
]=0;a
[0]++; a
[len
-1]++;}void mul(Com x
) {len
=MT
.mul(a
,a
,len
,x
.a
,x
.len
,mod
-1);}
};Com
solve(int l
,int r
) {Com ans
;if(l
==r
) {return ans
.init(a
[l
]+1),ans
;} else {int mid
=(l
+r
)>>1;ans
=solve(l
,mid
);ans
.mul(solve(mid
+1,r
));return ans
;}
}LL
qmi(LL a
,LL b
) {LL ans
=1;while(b
) {if(b
&1) ans
=ans
*a
%mod
;a
=a
*a
%mod
;b
>>=1;}return ans
%mod
;
}int main()
{
int _
; scanf("%d",&_
);while(_
--) {scanf("%d",&n
); all
=0; int mi
=INF
;for(int i
=1;i
<=n
;i
++) scanf("%d",&a
[i
]),mi
=min(mi
,a
[i
]);if(mi
==0) {puts("0");continue;}Com now
=solve(1,n
);LL ans
=1;for(int i
=2;i
<now
.len
;i
++) (ans
*=qmi(i
,now
.a
[i
]))%=mod
;printf("%lld\n",ans
);}return 0;
}
總結
以上是生活随笔為你收集整理的HDU - 7054 Yiwen with Formula 分治拆位FFT + dp + 费马小定理降幂的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。