無駄に難しく考えてしまったけどそう難しくなかった。
http://arc059.contest.atcoder.jp/tasks/arc059_c
問題
N人の幼児がそれぞれパラメータX[i]を持つとする。
F(X[0],X[1],....,X[N-1])とは、N人の幼児に飴を計C個配るときの各パターンにおいて、各幼児がa[i]個もらったとき、の総和とする。
幼児のパラメータのふり幅がA[i]≦X[i]≦B[i]である場合のFの総和、すなわちを求めよ。
解法
シンプルにA[i]=B[i]の場合を考えよう。
dp(k,n) := k番目までの幼児にn個の飴を配った場合、X[i]^a[i]の積の総和
とする。(k-1)番目までの幼児に(n-m)個の飴を配り、k番目の幼児にm個の飴を配ると考えると、
dp(k,n) += dp(k-1,n-m)*(A[i]^m)
のDPで解くことができる。これはO(N^3)のDP。
次にA[i]!=B[i]の場合だが、これは単に以下のようにDPの際の係数を変えるだけ。
dp(k,n) += dp(k-1,n-m)*(A[i]^m+(A[i]+1)^m+...+B[i]^m)
後半の和の部分を毎回計算するとO(N^4)になってTLEするので、前処理で累積和を取るなどしておこう。
int N,C; int A[404],B[404]; ll mo=1000000007; ll ppow[404][404]; ll ppowS[404][404]; ll dp[404][404]; void solve() { int i,j,k,l,r,x,y; string s; cin>>N>>C; FOR(i,N) cin>>A[i]; FOR(i,N) cin>>B[i]; ppow[0][0]=1; for(i=1;i<=400;i++) { ppow[i][0]=1; FOR(j,400) ppow[i][j+1]=ppow[i][j]*i%mo; } FOR(i,401) FOR(j,401) (ppowS[j+1][i]=ppowS[j][i]+ppow[j][i])%=mo; dp[0][0]=1; FOR(i,N) FOR(x,C+1) for(y=0;x+y<=C;y++) { ll p=(ppowS[B[i]+1][y]-ppowS[A[i]][y])%mo; if(p<0) p+=mo; (dp[i+1][x+y] += dp[i][x] * p) %= mo; } cout<<dp[N][C]<<endl; }
まとめ
もっと複雑な式変形がいるかと身構えて先にFの部分点取りに行ったけど、必要なかったな。