码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces Round448 D

时间:2017-11-30 23:38:30      阅读:156      评论:0      收藏:0      [点我收藏+]

标签:多少   logs   代码   存在   zab   pac   get   down   div   

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

*/

Codeforces Round448 D

标签:多少   logs   代码   存在   zab   pac   get   down   div   

原文地址:http://www.cnblogs.com/Crazycatmiao/p/7932210.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!