题目大意
给出一个长度为NNN, 由小写英文字母组成的字符串SSS, 求在所有由小写英文字母组成且长度为NNN且恰好有KKK位与SSS不同的字符串中,给定字符串TTT按照字典序排在第几位。
由于答案可能很大,模109+710^9 + 7109+7 输出。
题目解析
给定的字符串TTT实际上是取字典序小于TTT的所有字符串
先预处理出CiC_iCi,表示前iii位中,SSS串与TTT串之间的差异数
我们枚举每一位Ai(Ai<Ti)A_i(A_i<T_i)Ai(Ai<Ti),当AiA_iAi与SiS_iSi不同时,则iii位之后的允许的位数不同=K−C[i−1]−1=K-C[i-1]-1=K−C[i−1]−1,表示总共可以有KKK个差异,减去i−1i-1i−1前有多少位的差异再减去当前第iii位不同,所剩余的差异数XXX给剩下的串。Cab∗25a(a=X,b=n−i)C_a^b*25^a(a=X,b=n-i)Cab∗25a(a=X,b=n−i)
依次类推,就可以得出答案了。
因为要用到组合数学,又要除又要取模,所以要用乘法逆元,即a/b=a∗bpa/b=a*b^pa/b=a∗bp−^-−2^22(mod(mod(mod p)p)p)
代码
#include<bits/stdc++.h>
#define N 100005
#define M 1000000007
#define LL long long
using namespace std;
int n,k,ans;
LL a[N],b[N],p[N],ny[N],c[N],s[N];
string s1,s2;
LL qp(LL a,LL b)
{
LL c=1;
while(b)
{
if(b&1) (c*=a)%=M;
(a*=a)%=M;
b>>=1;
}
return c%M;
}
int main()
{
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
p[0]=ny[0]=c[0]=1;
for(int i=1;i<=100000;i++) p[i]=(p[i-1]*25)%M,c[i]=(c[i-1]*i)%M,ny[i]=qp(c[i],M-2);
cin>>n>>k>>s1>>s2;
for(int i=1;i<=n;i++) a[i]=s1[i-1]-'a',b[i]=s2[i-1]-'a';
for(int i=1;i<=n;i++) if(a[i]!=b[i]) s[i]=s[i-1]+1; else s[i]=s[i-1];
for(int i=1;i<=n;i++)
for(int j=0;j<26;j++)
if(j<b[i])
{
int x=k-s[i-1];
if(j!=a[i]) x--;
(ans+=(((c[n-i]*ny[x])%M)*ny[n-i-x]%M)*p[x]%M)%=M;
}
cout<<(ans+1)%M;
return 0;
}