【JZOJ4812】string

来源:互联网 发布:淘宝仓管的工作 编辑:程序博客网 时间:2024/05/20 07:58

Description

给出一个长度为n, 由小写英文字母组成的字符串S, 求在所有由小写英文字母组成且长度为n 且恰好有k 位与S 不同的字符串中,给定字符串T 按照字典序排在第几位。

由于答案可能很大,模10^9 + 7 输出。

Solution

转化题目,我们要求的就是字典序比T小且恰有k位和S不同的字符串个数。

我们假设当前做到第i位,前i1位与T相同。

如果Si=Ti,那么选的字符c须小于Ti,后面才可以随便选,个数为:Ck1ni25k1

如果SiTi,分两种情况,如果Si<Ti,那么分别计算相等和不等的情况,如果Si>Ti,则直接计算即可。

然后对于SiTi,我们让k减去1即可。

Code

#include<iostream>#include<cstdio>#include<cstdlib>#define fo(i,j,k) for(int i=j;i<=k;i++)#define fd(i,j,k) for(int i=j;i>=k;i--)#define N 100010#define mo 1000000007#define ll long longusing namespace std;char s[N],t[N];int a[N],b[N];ll mi[N],jc[N],ny[N];ll pow(ll m,int n){    ll b=1;    while(n)    {        if(n%2) b=b*m%mo;        n/=2;        m=m*m%mo;    }    return b;}ll c(int m,int n){    return jc[m]*ny[m-n]%mo*ny[n]%mo;}int main(){    freopen("string.in","r",stdin);    freopen("string.out","w",stdout);    int n,k;    cin>>n>>k;    scanf("%s",s+1);    scanf("%s",t+1);    jc[0]=mi[0]=ny[0]=1;    fo(i,1,n)    {        a[i]=s[i]-'a';        b[i]=t[i]-'a';        jc[i]=jc[i-1]*i%mo;        ny[i]=pow(jc[i],mo-2);        mi[i]=mi[i-1]*25%mo;    }    ll ans=1;    fo(i,1,n)    if(a[i]==b[i]) ans=(ans+b[i]*mi[k-1]%mo*c(n-i,k-1)%mo)%mo;    else    {        if(a[i]<b[i])        {            ans=(ans+(b[i]-1)*mi[k-1]%mo*c(n-i,k-1)%mo)%mo;            if(k<=n-i) ans=(ans+c(n-i,k)%mo*mi[k]%mo)%mo;        }        else ans=(ans+b[i]*mi[k-1]%mo*c(n-i,k-1)%mo)%mo;        k--;    }    cout<<ans;}
1 0
原创粉丝点击