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

55 篇文章 0 订阅
44 篇文章 0 订阅

Description

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

Input

第一行为两个整数n; k
第二行一个字符串S
第三行一个字符串T,(T即是k位与S不同的串)

Output

输出一行取模后的答案。

Sample Input

4 1
abcd
bbcd

Sample Output

76

Data Constraint

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

Solution

将字符串转换为26进制数来处理,就可以用数位DP的思想解决。
如果一个数比第二个数(设为b)小,那么一定是前面一段完全相同,一个小,后面随便
那么枚举小的这个位置,找到后面还必须有几个不同(设为q)。因为前面的数和b相同,所以可能已经有一些不同的,还有当前位枚举到是否相同,所以这个q不一定等于k
设还有m位数,那么答案加上 Cqm25q ,自己推推

Code

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define ll long long
#define fo(i,a,b) for(ll i=a;i<=b;i++)
#define N 101000
#define mo 1000000007
using namespace std;
ll ans=0,a[N],b[N],n,k,m25[N],m24[N],jc[N],ny[N],c[N];
char s[N],t[N];
ll mi(ll a,ll b)
{
    if(b==0) return 1ll;
    if(b==1) return a;
    ll k=mi(a,b/2);
    if(b%2==0) return (k*k)%mo;
    else return (((k*k)%mo)*a)%mo;
}
ll C(ll n,ll m){return (((jc[n]*ny[m])%mo)*ny[n-m])%mo;}
int main()
{
    freopen("string.in","r",stdin);
    freopen("string.out","w",stdout);
    m25[0]=jc[0]=ny[0]=m24[0]=1;
    fo(i,1,100000) m25[i]=(m25[i-1]*25)%mo,m24[i]=(m24[i-1]*24)%mo,jc[i]=(jc[i-1]*i)%mo,ny[i]=mi(jc[i],mo-2);
    scanf("%d%d\n",&n,&k);
    scanf("%s\n",s+1);scanf("%s\n",t+1);
    fo(i,1,n) a[i]=s[i]-97,b[i]=t[i]-97;
    fo(i,1,n) if(a[i]!=b[i]) c[i]=c[i-1]+1;else c[i]=c[i-1];
    fo(i,1,n)
    {
        fo(j,0,25)
        if(j<b[i])
        {
            int q=(k-c[i-1]);
            if(j!=a[i]) q--;
            ans=(ans+(C(n-i,q)*m25[q])%mo)%mo;
        }
    }
    printf("%lld",(ans+1)%mo);
    fclose(stdin);fclose(stdout);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值