Description
有两个长度为n且仅由小写字母组成的字符串S,T,满足S和T恰好有k位不同。问在所有恰好与S有k位不同的字符串中,T按照字典序排在第几位。由于答案可能很大,模10^9+7输出。
Input
第一行两个整数n,k。
第二行一个字符串S。
第三行一个字符串T。
Output
一行一个整数表示答案。
Hint
对于前30%的数据,n<=5.
对于100%的数据,k<=n<=100000.
Source
BY BPM
Solution
看到这种类型的题目毫无想法,几乎没有接触过。。
首先说一个结论,与长度为n的串有k位不同的串共有 Ckn∗25k 个,这玩意推一推就出来了。
想要知道T的排名,只需要计算前面有多少个串就可以了。考虑当前做到i位,那么如果S的第i位比T的第i位要小,那么第一位对答案的贡献就是
Cn−1m−1∗25m−1∗(T[1]−′a′−1)+Cn−1m∗25m
然后要m–
如果S的第i位比T的第i位要大,那么第一位对答案的贡献就是 Cn−1m−1∗25m−1∗(T[1]−′a′) 然后要m–
如果S的第i位等于T的第i位,那么对答案的贡献就是
Cn−1m−1∗25m−1∗(T[1]−′a′)
然后往下一位一样的接着处理就好了。
考虑到要对组合数取模,即对分数取模,这里用到了乘法逆元解决,即 ab%c 与 a∗bϕ(c)−1%c 是等价的,这里1e9+7是质数,所以 ϕ(109+7)=109+6 。快速幂搞定
Code
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <queue>
#include <vector>
#include <algorithm>
#define rep(i, st, ed) for (int i = st; i <= ed; i += 1)
#define drp(i, st, ed) for (int i = st; i >= ed; i -= 1)
#define erg(i, st) for (int i = ls[st]; i; i = e[i].next)
#define fill(x, t) memset(x, t, sizeof(x))
#define max(x, y) (x)>(y)?(x):(y)
#define min(x, y) (x)<(y)?(x):(y)
#define ll long long
#define db double
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define N 100001
#define E 50001
#define L 256
char s[N], t[N];
ll biao[N];
inline ll pw(int dep, ll x){
if (dep == 0){return 1;}
if (dep == 1){return x;}
ll tmp = pw(dep / 2, x);
if (dep & 1){return ((tmp*tmp)%MOD*x)%MOD;}
return (tmp*tmp)%MOD;
}
inline ll C(int n, int m){
if (n < 0 || m < 0 || n < m){return 0;}
ll tmp = pw(MOD - 2, biao[n-m]*biao[m]%MOD);
(tmp *= biao[n])%=MOD;
(tmp *= pw(m, 25))%=MOD;
return tmp;
}
int main(void){
int n, m;
scanf("%d %d",&n,&m);
scanf("%s", s);
scanf("%s", t);
biao[0] = 1;
rep(i, 1, n){
biao[i] = biao[i - 1] * i%MOD;
}
ll ans = 0;
rep(i, 0, n - 1){
if (s[i] < t[i]){
(ans += C(n-i-1,m)%MOD)%=MOD;
(ans += (t[i]-'a'-1)*C(n-i-1,m-1)%MOD)%=MOD;
}
else{
(ans += (t[i]-'a')*C(n-i-1,m-1)%MOD)%=MOD;
}
m -= (s[i] != t[i]);
}
printf("%lld\n", (ans+1)%MOD);
return 0;
}