3問目がしっかりと解けきれずTシャツならず。
https://www.hackerrank.com/contests/hourrank-20/challenges/p-string
問題
文字列Sが与えられる。
Sの空でないsubsequenceのうち、'a'と'b'の数が等しく、'c'と'd'の数が等しいものは何通りあるか。
解法
A,B,C,DをS中の'a','b','c','d'の数とし、Xをそれ以外の文字の数とする。
答えは下記の積から、空文字列分1を引いたものである。
- 'a'と'b'の登場回数が等しいケース通り
- 'c'と'd'の登場回数が等しいケース通り
- その他の文字はあってもなくてもよいので通り
ll mo=1000000007; ll combi(ll N_, ll C_) { const int NUM_=1000001; static ll fact[NUM_+1],factr[NUM_+1],inv[NUM_+1]; if (fact[0]==0) { inv[1]=fact[0]=factr[0]=1; for (int i=2;i<=NUM_;++i) inv[i] = inv[mo % i] * (mo - mo / i) % mo; for (int i=1;i<=NUM_;++i) fact[i]=fact[i-1]*i%mo, factr[i]=factr[i-1]*inv[i]%mo; } if(C_<0 || C_>N_) return 0; return factr[C_]*fact[N_]%mo*factr[N_-C_]%mo; } int Q; string S; int N; ll num[5]; void solve() { int i,j,k,l,r,x,y; string s; cin>>Q; while(Q--) { cin>>S; N=S.size(); ZERO(num); ll A=0,B=0,C=1; FORR(c,S) { if(c=='a') num[0]++; else if(c=='b') num[1]++; else if(c=='c') num[2]++; else if(c=='d') num[3]++; else C=C*2%mo; } FOR(i,min(num[0],num[1])+1) (A += combi(num[0],i)*combi(num[1],i))%=mo; FOR(i,min(num[2],num[3])+1) (B += combi(num[2],i)*combi(num[3],i))%=mo; cout<<(A*B%mo*C%mo+(mo-1))%mo<<endl; } }
まとめ
ここまではすんなり。