【NOIP2016提高A组五校联考2】string
题目
给出一个长度为n, 由小写英文字母组成的字符串S, 求在所有由小写英文字母组成且长度为n 且恰好有k 位与S 不同的字符串中,给定字符串T 按照字典序排在第几位。
由于答案可能很大,模10^9 + 7 输出。
分析
我们从小到大枚举i,
假设1i-1位都是等于T的1i-1位,那么第i位就要小于T[i],
然后在保证不用的个数等于k的情况下,i+1~n位就可以随便选。
细节很多,小心处理。
#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const int maxlongint=2147483647;
const long long mo=1000000007;
const int N=100005;
using namespace std;
long long k,n,a[N],d[N],jc[N],ny[N],ans=1;
bool q;
char s2[N],s1[N];
long long mi(long long x,long long y)
{
long long sum=1;
while(y)
{
if(y&1) sum=sum*x%mo;
x=x*x%mo;
y/=2;
}
return sum;
}
long long c(int x,int y)
{
return jc[x]*ny[y]%mo*ny[x-y]%mo;
}
int pre()
{
jc[0]=1;
for(int i=1;i<=N;i++)
{
jc[i]=jc[i-1]*i%mo;
ny[i]=mi(jc[i],mo-2);
}
ny[0]=ny[1];
d[0]=1;
for(int i=1;i<=N;i++) d[i]=d[i-1]*25%mo;
}
int main()
{
pre();
scanf("%lld%lld",&n,&k);
scanf("%s",s1+1);
scanf("%s",s2+1);
for(int i=1;i<=n;i++)
{
a[i]=a[i-1];
if(s1[i]!=s2[i]) a[i]++;
}
for(int i=1;i<=n;i++)
if(s1[i-1]==s2[i-1])
q=true;
for(int i=1;i<=n;i++)
{
if(s1[i]==s2[i])
{
(ans+=(s2[i]-'a')*d[k-1]%mo*c(n-i,k-1)%mo)%mo;
}
else
if(s1[i]<s2[i])
{
(ans+=((s2[i]-'a'-1)*d[k-1]%mo*c(n-i,k-1)%mo)%mo)%mo;
if(k<=n-i) ans=(ans+d[k]*c(n-i,k)%mo)%mo;
k--;
}
else
if(s2[i]<s1[i])
{
(ans+=(s2[i]-'a')*d[k-1]%mo*c(n-i,k-1)%mo)%mo;
k--;
}
}
cout<<ans%mo<<endl;
}