【JZOJ 4812】【NOIP2016提高组 五校联考2】string

来源:互联网 发布:算法导论 中文版 pdf 编辑:程序博客网 时间:2024/05/01 09:54

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;}
0 0