Description
给出一个长度为n, 由小写英文字母组成的字符串S, 求在所有由小写英文字母组成且长度为n 且恰好有k 位与S 不同的字符串中,给定字符串T 按照字典序排在第几位。
由于答案可能很大,模10^9 + 7 输出。
Input
第一行为两个整数n; k
第二行一个字符串S
第三行一个字符串T,(T即是k位与S不同的串)
Output
输出一行取模后的答案。
Sample Input
4 1
abcd
bbcd
Sample Output
76
Data Constraint
对于前30% 的数据,n<=5
对于100% 的数据,k<=n<=10^5
Solution
将字符串转换为26进制数来处理,就可以用数位DP的思想解决。
如果一个数比第二个数(设为b)小,那么一定是前面一段完全相同,一个小,后面随便
那么枚举小的这个位置,找到后面还必须有几个不同(设为q)。因为前面的数和b相同,所以可能已经有一些不同的,还有当前位枚举到是否相同,所以这个q不一定等于k
设还有m位数,那么答案加上
Cqm∗25q
,自己推推
Code
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define ll long long
#define fo(i,a,b) for(ll i=a;i<=b;i++)
#define N 101000
#define mo 1000000007
using namespace std;
ll ans=0,a[N],b[N],n,k,m25[N],m24[N],jc[N],ny[N],c[N];
char s[N],t[N];
ll mi(ll a,ll b)
{
if(b==0) return 1ll;
if(b==1) return a;
ll k=mi(a,b/2);
if(b%2==0) return (k*k)%mo;
else return (((k*k)%mo)*a)%mo;
}
ll C(ll n,ll m){return (((jc[n]*ny[m])%mo)*ny[n-m])%mo;}
int main()
{
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
m25[0]=jc[0]=ny[0]=m24[0]=1;
fo(i,1,100000) m25[i]=(m25[i-1]*25)%mo,m24[i]=(m24[i-1]*24)%mo,jc[i]=(jc[i-1]*i)%mo,ny[i]=mi(jc[i],mo-2);
scanf("%d%d\n",&n,&k);
scanf("%s\n",s+1);scanf("%s\n",t+1);
fo(i,1,n) a[i]=s[i]-97,b[i]=t[i]-97;
fo(i,1,n) if(a[i]!=b[i]) c[i]=c[i-1]+1;else c[i]=c[i-1];
fo(i,1,n)
{
fo(j,0,25)
if(j<b[i])
{
int q=(k-c[i-1]);
if(j!=a[i]) q--;
ans=(ans+(C(n-i,q)*m25[q])%mo)%mo;
}
}
printf("%lld",(ans+1)%mo);
fclose(stdin);fclose(stdout);
}