NOIP提高组【JZOJ4812】string

来源:互联网 发布:西安交大大数据学院 编辑:程序博客网 时间:2024/06/05 18:13

Description

给出一个长度为n, 由小写英文字母组成的字符串S, 求在所有由小写英文字母组成且长度为n 且恰好有k 位与S 不同的字符串中,给定字符串T 按照字典序排在第几位。由于答案可能很大,模109+7 输出。

Data Constraint

对于前30% 的数据,n<=5
对于100% 的数据,k<=n<=10^5

Solution

这道题我们直接算就好啦。考虑将数量不断逼近值T,假设现在还能修改m次,对于当前的的一位Si和Ti

假设Si!=Ti,那么显然第i位比Ti小的都比T所在排名前,那么我们直接加(Tia)25m1Cm1ni。特别的,当Ti>Si,显然当第i位为Si时是不用修改的,所以方案即是(Tia1)25m1Cm1ni+25mCmni。最后只要将m减一即可。

假设Si=Ti,那么显然第i位Ti小的都比T所在排名前,那么我们直接加(Tia)25m1Cm1ni

代码

#include<iostream>#include<cmath>#include<cstring>#include<cstdio>#include<algorithm>#define ll long longusing namespace std;const ll maxn=100005,mo=1000000007;char s[maxn],t[maxn];int n,m,i,j,k,l,x,y;ll f[maxn],g[maxn],ans;ll mi(ll x,int y){    if (y==1) return x;    ll t=mi(x,y/2);    if (y%2) return t*t%mo*x%mo;return t*t%mo;}ll c(ll x,ll y){    return f[x]*mi(f[y],mo-2)%mo*mi(f[x-y],mo-2)%mo;}int main(){    freopen("string.in","r",stdin);freopen("string.out","w",stdout);    //freopen("data.in","r",stdin);    scanf("%d%d\n",&n,&m);    scanf("%s\n",s+1);    scanf("%s\n",t+1);    f[0]=1;g[0]=1;    for (i=1;i<=n;i++)        f[i]=f[i-1]*i%mo,g[i]=g[i-1]*25%mo;    for (i=1;i<=n;i++)        if (s[i]!=t[i]){            if (s[i]>t[i]) ans=(ans+(t[i]-97)*g[m-1]%mo*c(n-i,m-1)%mo)%mo;            else{                ans=(ans+(t[i]-98)*g[m-1]%mo*c(n-i,m-1)%mo)%mo;                ans=(ans+g[m]*c(n-i,m)%mo)%mo;            }            m--;        }else ans=(ans+(t[i]-97)*g[m-1]%mo*c(n-i,m-1)%mo)%mo;    ans++;    printf("%d\n",ans);}
3 0