给你串a串b,问用a的排列生成新串c满足字典序a<c<b的串c种类数
问题转化成问f(s),表示用已有字符构建的字符串字典序上小于s,答案就是f(b)-f(a)-1
这样一转化就不用枚举两个字典序变化点了。。
然后i枚举字典序变化点,j枚举字符集
由于字典序变化点越靠后贡献越小,所以维护一个cur表示当前可用字符生成的不同字符串个数,
每当决定一个字符,cur就要除掉剩下字符的个数,再乘上这个要用的字符的剩余个数
#include<bits/stdc++.h>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<iostream>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<iomanip>
using namespace std;
#define ll long long
#define pb push_back
#define FOR(a) for(int i=1;i<=a;i++)
#define sqr(a) (a)*(a)
const int inf=0x3f3f3f3f;
const int maxn=1e6+5;
const int mod=1e9+7;
int n;
char a[maxn],b[maxn];
int cnt[26],c[26];
int fac[maxn],rfac[maxn],save_rev[maxn];
int f(char *s){
memcpy(c,cnt,sizeof c);
int cur=fac[n];
for(int i=0;i<26;i++){
if(c[i])
cur=1ll*cur*rfac[c[i]]%mod;
}
//cur是剩下字符可构成字符串种数
int ans=0;
for(int i=1;i<=n;i++){ //枚举不同位置
for(int x=0;x<s[i]-'a';x++){
if(c[x]){ //枚举比他小的字符
int now=cur;
now=1ll*now*save_rev[n-i+1]%mod; //选定一种字符
now=1ll*now*c[x]%mod; //选哪一个
ans=(ans+now)%mod;
}
}
if(c[s[i]-'a']){
cur=1ll*cur*save_rev[n-i+1]%mod;
cur=1ll*cur*c[s[i]-'a']%mod;
c[s[i]-'a']--;
}else{
break;
}
}
return ans;
}
int rev(int a){
int ret=1;
for(int b=mod-2;b;b>>=1,a=(ll)a*a%mod)
if(b&1)
ret=(ll)ret*a%mod;
return ret;
}
int main(){
fac[0]=rfac[0]=1;
for(int i=1;i<maxn;i++){
fac[i]=(ll)i*fac[i-1]%mod;
save_rev[i]=rev(i);
rfac[i]=(ll)save_rev[i]*rfac[i-1]%mod;
}
scanf("%s%s",a+1,b+1);
n=strlen(a+1);
for(int i=1;i<=n;i++){cnt[a[i]-'a']++;}
printf("%d\n",(f(b)-f(a)-1+mod)%mod);
}