16年北京现场赛的题,全场过的队30+。
初看只知道 O(N^2logK)的暴力,以为是什么变换。
仔细发现活用 二项式定理 就行。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define fst first 4 #define scd second 5 #define pb(x) push_back((x)) 6 #define mkp(x,y) make_pair((x),(y)) 7 #define ist(x) insert((x)) 8 typedef long long ll; 9 typedef pair<int ,int > pii; 10 typedef pair<ll ,ll > pll; 11 typedef vector< int > vi; 12 ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);} 13 ll qPow(ll a,ll b,ll mod){ ll ret=1ll;while(b){ if(b&1) ret=ret*a%mod;a=a*a%mod;b>>=1;} return ret; } 14 15 const ll mod=1e9+7; 16 const int maxn=5e4+4; 17 ll P[maxn][128]; // P[i][k] 代表 前i个数字之和的k次方 18 ll Pre[maxn][128];// Pre[i][k] 代表 前i个P[i][k]的和 19 ll F[128],INV[128]; 20 char raw[maxn]; 21 int N,K; 22 23 void init(){ 24 P[0][0]=1; 25 for(int i=1;i<=N;++i){ 26 P[i][0]=1; 27 P[i][1]=(P[i-1][1]+raw[i-1]-'0')%mod; 28 for(int j=2;j<=K;++j) 29 P[i][j]=P[i][j-1]*P[i][1]%mod; 30 } 31 32 Pre[0][0]=1;// 0^0 =1 33 for(int j=0;j<=K;++j){ 34 for(int i=1;i<=N;++i) 35 Pre[i][j]=(Pre[i-1][j]+P[i][j])%mod; 36 } 37 } 38 39 ll getC(int i,int j){ 40 if(j==0) return 1ll; 41 return F[i]*INV[i-j]%mod*INV[j]%mod; 42 } 43 44 int main(){ 45 46 F[0]=1ll; 47 for(ll i=1;i<=100;++i) 48 F[i]=F[i-1]*i%mod; 49 INV[100]=qPow(F[100],mod-2,mod); 50 for(ll i=99;i>=0;i--) 51 INV[i]=(i+1)*INV[i+1]%mod; 52 53 int Tests; 54 scanf("%d",&Tests); 55 while(Tests--){ 56 scanf("%d%d",&N,&K); 57 scanf("%s",raw); 58 init(); 59 ll ans; 60 for(int i=1;i<=N;++i){ 61 ans=0ll; 62 for(int j=0;j<=K;++j){ 63 if(j&1) 64 ans=(ans-getC(K,j)*P[i][K-j]%mod*Pre[i-1][j]%mod+mod)%mod; 65 else 66 ans=(ans+getC(K,j)*P[i][K-j]%mod*Pre[i-1][j]%mod)%mod; 67 } 68 printf("%lld%c",ans,i==N?' ':' '); 69 } 70 } 71 return 0; 72 }
(代码写的常数有点大,应该是mod多了,,,