Description
给出一个长度为n, 由小写英文字母组成的字符串S, 求在所有由小写英文字母组成且长度为n 且恰好有k 位与S 不同的字符串中,给定字符串T 按照字典序排在第几位。
由于答案可能很大,模10^9 + 7 输出。
对于100% 的数据,k<=n<=10^5
Analysis
其实扫一遍就好了。
一开始好傻没想到正解比赛过了1.5h才恍然大悟。
其实就是算有多少个串比该串小,那么类似于数位DP的思路,就会发现没了限制之后方案数可以O(1)算。主要看代码吧。
Code
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int N=100010,mo=1e9+7;
char a[N],b[N];
ll n,k,fac[N];
ll qmi(ll x,ll n)
{
ll t=1;
for(;n;n>>=1)
{
if(n&1) t=t*x%mo;
x=x*x%mo;
}
return t;
}
ll ny(ll x)
{
return qmi(x,mo-2);
}
ll calc(ll n,ll k)
{
if(n<k) return 0;
return qmi(25,k)*fac[n]%mo*ny(fac[k]*fac[n-k]%mo)%mo;
}
int main()
{
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
scanf("%lld %lld",&n,&k);
fac[0]=1;
fo(i,1,n) fac[i]=fac[i-1]*i%mo;
scanf("%s\n%s",a+1,b+1);
ll ans=0;
fo(i,1,n)
{
if(a[i]<b[i])
{
ans=(ans+(b[i]-'a'-1)*calc(n-i,k-1)%mo+calc(n-i,k))%mo;
k--;
}
else
{
ans=(ans+(b[i]-'a')*calc(n-i,k-1)%mo)%mo;
if(a[i]>b[i]) k--;
}
if(!k) break;
}
printf("%lld",ans+1);
return 0;
}