貝殼找房計數比賽&&祭facinv
阿新 • • 發佈:2018-06-30
比賽 margin 去重 次數 格式 AD 事情 print itl
震驚!階乘逆元處理背後竟有如此玄機……
題目描述
貝殼找房舉辦了一場計數比賽,比賽題目如下。
給一個字符串 s 和字符串 t,求出 s 的所有去重全排列中 t 出現的次數。比如aab
的去重全排列為aab
、aba
、baa
。註意aaaa
算出現兩次aaa
。
你的老大希望你幫他寫一個程序作弊。
輸入格式
第一行一個整數 TT,表示數據組數。
每組數據中,第一行一個字符串 ss,第二行一個字符串 tt。
數據保證 1≤T≤100, 1≤∣t∣≤∣s∣≤105,t,s 只包含小寫字母。
輸出格式
輸出一共 TT 行,每行一個整數,表示所求答案對 10^9+7取模的結果。
樣例輸入
2 aab ab aabb ab
樣例輸出
2 6
題目分析
其實就是一道挺簡單的數論基礎題……
但是復賽時候我想復雜了很多,一直在考慮將目標串拆成多個原串後如何去重之類的問題。
例如原串=ab,目標串=ababaa。然後設t=ab,目標串就有taaab/ttaa這兩種情況,於是陷入去重無法自拔……
呃實際上冷靜分析就可以發現,只用考慮拆一次的結果,那麽就套上可重全排列的公式就好了。
1 #include<bits/stdc++.h> 2 constlong long MO = 1e9+7; 3 const long long maxn = 100035; 4 5 long long ans,inv[maxn],mp[maxn]; 6 int n,tt; 7 char s[maxn],t[maxn]; 8 bool fl; 9 10 int main() 11 { 12 inv[0] = inv[1] = 1; 13 for (int i=2; i<maxn; i++) 14 inv[i] = (long long)(MO-MO/i)*inv[MO%i]*inv[i-1]%MO; 15 scanf("%d",&tt); 16 while (tt--) 17 { 18 fl = 0; 19 memset(mp, 0, sizeof mp); 20 scanf("%s%s",s,t); 21 for (int i=0; s[i]; i++) 22 mp[s[i]]++; 23 for (int i=0; t[i]; i++) 24 mp[t[i]]--, fl = fl||(mp[t[i]]<0); 25 if (fl){ 26 printf("0\n"); 27 continue; 28 } 29 n = strlen(s)-strlen(t); 30 ans = n+1; 31 while (n--) ans = ans*(n+1)%MO; 32 for (char i=‘a‘; i<=‘z‘; i++) 33 ans = (long long)ans*inv[mp[i]]%MO; 34 printf("%lld\n",ans); 35 } 36 return 0; 37 }
然而!上面這個程序是會WA的!
在歷經好長一段時間的調試之後,終於發現facinv中間溢出了……
那麽大不了就改成這樣嘛,反正是多一個%MO的事情
1 inv[0] = inv[1] = 1; 2 for (int i=2; i<maxn; i++) 3 inv[i] = (MO-MO/i)%MO*inv[MO%i]%MO*inv[i-1]%MO;
可是依舊WA :)
1 inv[0] = inv[1] = 1; 2 for (int i=2; i<maxn; i++) 3 inv[i] = (MO-MO/i)%MO*inv[MO%i]%MO; 4 for (int i=2; i<maxn; i++) inv[i] = inv[i-1]*inv[i]%MO;
最後只能改成上面這個樣子……
行吧終於過了。
END
貝殼找房計數比賽&&祭facinv