【JZOJ4812】string

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 long
using 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;
}
posted @ 2016-10-10 19:14  sadstone  阅读(35)  评论(0编辑  收藏  举报