您的位置:首页 > 其它

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

2016-10-06 22:00 561 查看

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