Codeforces Round448 D

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]!\times cnt[2]!\times cnt[3]!\times \cdots \times cnt[n]!}\) ,而当前的则为\(\cfrac{(n-pos-1)!}{cnt[1]!\times cnt[2]!\times cnt[3]!\times \cdots \times (cnt[i]-1)! \times \cdots \times cnt[n]!}\) ,其中i为当前选的字符,pos位选的位置,从0开始

那么当前的就等于之前的\(\times \cfrac{(n-pos-1)!}{(n-pos)!}\times \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\n",ans);
	return 0;
}
/*
abacaba
ubuduba

abazaba
zbzzzba

*/
posted @ 2017-11-30 22:25  CRAZYC4T  阅读(208)  评论(0编辑  收藏  举报