2016年ACM/ICPC北京賽區 I題(思維 二項式展開)
阿新 • • 發佈:2018-11-11
題意:給你一個只由0~9字元構成的長度為n(n<=50000)的字串a,
定義,求對於每個i(i=1,2,...,n) ,輸出。答案對1e9+7取模。
由題意,存在表示式
令s[i]為a[i]的字首和,再進行二項式展開,則有
因此
組合數可以O(k^2)預處理,s[i]可以O(n)預處理,s[i]^k可以O(n*k)預處理,s[i]^k的字首和也可以O(n*k)預處理,對於每個i,O(k)計算ans[i],總複雜度為O(n*k)
程式碼:
#include<bits/stdc++.h> #define ll long long using namespace std; const ll mo=1e9+7; const int maxn=50010; ll s[maxn],ss[maxn][101],sss[maxn][101]; ll c[101][101],n,k; char a[maxn]; void init() { for(int i=0;i<=100;i++) { c[i][0]=1; for(int j=1;j<=i;j++) { c[i][j]=(c[i-1][j]+c[i-1][j-1])%mo; } } } int main() { init(); int T,cas=1; scanf("%d",&T); while(T--) { scanf("%lld%lld",&n,&k); getchar(); scanf("%s",a+1); s[0]=0; for(ll i=1;i<=n;i++) { s[i]=s[i-1]+(a[i]&15); } for(ll i=1;i<=n;i++) { ss[i][0]=1; sss[i][0]=0; for(ll j=1;j<=k;j++) { ss[i][j]=(ss[i][j-1]*s[i])%mo; sss[i][j]=(sss[i-1][j]+ss[i][j])%mo; } } for(ll i=1;i<=n;i++) { ll ans=i*c[k][0]%mo*ss[i][k]%mo; ll tmp; for(ll j=1;j<=k;j++) { if(j&1) tmp=-sss[i-1][j]; else tmp=sss[i-1][j]; ans=(ans+(c[k][j]*ss[i][k-j]%mo*tmp)%mo)%mo; } ans=(ans+mo)%mo; printf("%lld%c",ans,i==n?'\n':' '); } } return 0; }