Codeforces Round448 D
题目大意
有两个长度相同的字符串a,b(长度不超过1e6),构造一个字符串c,使得c是a的重排序,并且c的字典序大于a,c的字典序小于b,问共有多少种构造的方法,答案对1e9+7取模
思路
若只考虑c>a,那么从前往后遍历,如果当前取了一个(c_i>a_i) ,那么之后的所有排法都成立(用组合数求);如果当前(c_i=a_i) ,那么就再往下一个考虑。
同理,若只考虑c<b是一样的。
那么可以用两个标记igna和ignb来表示是否忽视a、b的存在,当(c_i=a_i) 时,并且igna为0时,就往下一个考虑,并根据(c_i) 是否小于(b_i) 来修改下一个的ignb值;(c_i=b_i) 则同理,反之则为所有排放都成立的情况。
这种算法需要枚举每一位,在当前为枚举26个字母,在求组合数时也需要枚举26个字母的排法,时间复杂度是(O(n*k^2)),n=1e6,k=26,是超时的。
优化:考虑到在求组合数时,不需要每次从头算一遍,而可以在一开始记录全排列的情况,每枚举一位,记录用掉当前的(c_i)后的组合数。
假设字母的个数为cnt[i]。一开始的全排列为(C(n,cnt[1])*C(n-cnt[1],cnt[2])*C(n-cnt[1]-cnt[2],cnt[3])* cdots C(n-cnt[1]-cnt[2]-cdots -cnt[n-1],cnt[n])) ,其中,(n-cnt[1]-cnt[2]-cdots -cnt[n-1] = cnt[n]) ,化简后为(cfrac{(n-pos)!}{cnt[1]! imes cnt[2]! imes cnt[3]! imes cdots imes cnt[n]!}) ,而当前的则为(cfrac{(n-pos-1)!}{cnt[1]! imes cnt[2]! imes cnt[3]! imes cdots imes (cnt[i]-1)! imes cdots imes cnt[n]!}) ,其中i为当前选的字符,pos位选的位置,从0开始
那么当前的就等于之前的( imes cfrac{(n-pos-1)!}{(n-pos)!} imes cfrac{cnt[i]!}{(cnt[i]-1)!}) ,即可。
代码
//http://codeforces.com/contest/895/problem/D
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<queue>
#include<vector>
#include<map>
#define MAXN 1000005
const int inf=0x3f3f3f3f;
#define rep(i,n) for(i=0;i<n;i++)
#define mem(a,x) memset(a,x,sizeof(a))
const double PI=acos(-1);
const double eps=1e-9;
using namespace std;
typedef long long ll;
const ll Mod = 1e9+7;
int t,i,j,k,n,m,num[300];
ll ans;
char a[MAXN],b[MAXN],c[MAXN];
int fac[MAXN],inv[MAXN];
int fp(int a,int k)
{
int res=1;
while(k)
{
if(k&1)res=1LL*res*a%Mod;
a=1LL*a*a%Mod;
k>>=1;
}
return res;
}
void build()
{
for(int i=(fac[0]=1);i<(MAXN);i++)
fac[i]=1LL*i*fac[i-1]%Mod;
inv[MAXN-1]=fp(fac[MAXN-1],Mod-2);
for(int i=MAXN-2;i>=0;i--)
inv[i]=1LL*(i+1)*inv[i+1]%Mod;
}
int C(int n,int k)
{
return 1LL*fac[n]*inv[k]%Mod*inv[n-k]%Mod;
}
ll cal(int x){
ll cnt=1;
int d=n-x-1;
for(char i='a';i<='z';i++){
if(num[i]){
cnt*=C(d,num[i]);
cnt%=Mod;
d-=num[i];
}
}
return cnt;
}
int dfs(int pos,int igna,int ignb,int cc){
if(pos==n){
return 0;
}
char l=a[pos],r=b[pos];
//if(igna||ignb){
if(igna) l='a';
if(ignb) r='z';
//}
for(char i=l;i<=r;i++){
if(!num[i]) continue;
int nxc=1LL*cc*fac[n-pos-1]%Mod*inv[n-pos]%Mod*fac[num[i]]%Mod*inv[num[i]-1]%Mod;
if(i==a[pos]&&(!igna)){
num[i]--;
dfs(pos+1,0,ignb||(i<b[pos]),nxc);
num[i]++;
}
else if(i==b[pos]&&(!ignb)){
num[i]--;
dfs(pos+1,igna||(i>a[pos]),0,nxc);
num[i]++;
}
else{
num[i]--;
ans+=nxc;
ans%=Mod;
num[i]++;
}
}
}
int main(){
build();
scanf("%s%s",a,b);
n=strlen(a);
ans=0;
for(int i=0;i<n;i++){
num[a[i]]++;
}
int cc=fac[n];
for(int i='a';i<='z';i++){
if(num[i]){
cc=1LL*cc*inv[num[i]]%Mod;
}
}
dfs(0,0,0,cc);
printf("%lld
",ans);
return 0;
}
/*
abacaba
ubuduba
abazaba
zbzzzba
*/