1. 程式人生 > >貝殼找房計數比賽&&祭facinv

貝殼找房計數比賽&&祭facinv

比賽 margin 去重 次數 格式 AD 事情 print itl

震驚!階乘逆元處理背後竟有如此玄機……

題目描述

貝殼找房舉辦了一場計數比賽,比賽題目如下。

給一個字符串 s 和字符串 t,求出 s 的所有去重全排列中 t 出現的次數。比如aab的去重全排列為aabababaa。註意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 const
long 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