読者です 読者をやめる 読者になる 読者になる

土下座しながら探索中

主に競技プログラミング

SRM Div2 hard : VocaloidsAndSongs

SRM

問題概要:
S個の歌がある
その音楽を3人のボーカロイドGumi, Ia, Mayuが歌う
Gumi は gumi回、 Ia は ia回、 Mayu は mayu回だけ歌う
S個の歌は少なくとも3人のうち1人に歌われなければならない
そのような歌に対するボーカロイドの割り当て方は何通り存在するか
答えは大きくなるので1000000007でmodをとること

解法:
以下の図について考える

aはGumiだけが歌う曲の数
bはIaだけが歌う曲の数
cはMayuだけが歌う曲の数
dはGumiとIaだけが歌う曲の数
eはGumiとMayuだけが歌う曲の数
fはMayuとIaだけが歌う曲の数
gはGumiとIaとMayuの3人が歌う曲の数

ここでd,e,f,gをループで決めてしまう(最大50*50*50*50)
これさえ決まればSをつかってa,b,cは復元できる
答えはそれら全てのd,e,f,gに対する組み合わせとなるので、
C[S][a] * C[S-a][b] * C[S-a-b][c] * C[S-a-b-c][d] * C[S-a-b-c-d][e] * C[S-a-b-c-d-e][f] * C[S-a-b-c-d-e-f][g]の総和となる
C[a][b]はコンビネーション aCb
掛け算の際にオーバーフローしないように注意すること

コード:

typedef long long ll;
typedef pair<int,int> ii;
typedef vector<int> vi;
typedef vector<vector<int> > vvi;

ll C[MAX][MAX];
 
class VocaloidsAndSongs {
public:

  ll modmultiply(ll a,ll b) {
    ll c = MOD;
    ll x = 0,y = a%c; 
    while(b > 0) {
      if(b%2 == 1) {
	x = (x+y)%c;  }
      y = (y*2)%c;
      b /= 2; }
    return x%c;  
  }

  void makeC()
  {
    C[0][0] = 1;
    rep(i,MAX-1)rep(j,i+1)
      {
	C[i+1][j] += C[i][j]%MOD;
	C[i+1][j] %= MOD;
	if(j+1<MAX){
	  C[i+1][j+1] += C[i][j]%MOD;
	  C[i+1][j+1] %= MOD;
	}
      }
  }

  int count( int S, int gumi, int ia, int mayu ) {
    makeC();

    ll ans = 0;
    rep(d,S+1){
      rep(e,S+1){
	if(d+e > S)break;
	rep(f,S+1){
	  if(d+e+f > S)break;
	  rep(g,S+1){
	    if(d+e+f+g > S)break;
	    int a = gumi - (d+g+e);
	    if(a < 0)continue;
	    int b = ia - (d+g+f);
	    if(b < 0)continue;
	    int c = mayu - (e+g+f);
	    if(c < 0)continue;

	    if(a+b+c+d+e+f+g != S)continue;
	    if( a < 0 || b < 0 || c < 0 || d < 0 || e < 0 || f < 0 || g < 0)continue;

	    ll value = 1;
	    value = modmultiply(value,C[S][a]);
	    value = modmultiply(value,C[S-a][b]);
	    value = modmultiply(value,C[S-a-b][c]);
	    value = modmultiply(value,C[S-a-b-c][d]);
	    value = modmultiply(value,C[S-a-b-c-d][e]);
	    value = modmultiply(value,C[S-a-b-c-d-e][f]);
	    value = modmultiply(value,C[S-a-b-c-d-e-f][g]);
	    ans = ( ans + value ) % MOD;
	  }
	}
      }
    }
    return ans%MOD;
  }

};