您的位置:首页 > 其它

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

2016-10-05 21:22 381 查看

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位数,那么答案加上Cqm∗25q,自己推推

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
,b
,n,k,m25
,m24
,jc
,ny
,c
;
char s
,t
;
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
*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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: