簡要題意:
請你對滿足下列條件的正整數序列 進行計數。
- 令 給出 進制數字集合 ,滿足要求的 的 進制拆分中的所有數字都應該屬於 集合。
題解:
首先高精度是跑不掉的了。。。
由於 很小,可以考慮把問題轉化成只有下界進行容斥。
設 爲所有下界之和+1 ,假設總和爲 ,由於沒有上界,顯然方案數就是 ,用隔板法考慮即可。
那麼每一次要求的東西就是
考慮範德蒙德恆等式 : ,這個等式在廣義組合數上仍然成立。
於是我們只需要用數位DP,求出 ,然後用 來計算即可。
DP過程中的轉移也需要依賴範德蒙德恆等式。
複雜度 ,高精度不是複雜度瓶頸。
代碼:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
using std::cerr;
using std::cout;
cs int mod=1e9+7;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(int a,int b){return a-b<0?a-b+mod:a-b;}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline void Inc(int &a,int b){a+=b-mod;a+=a>>31&mod;}
inline void Dec(int &a,int b){a-=b;a+=a>>31&mod;}
inline void Mul(int &a,int b){a=mul(a,b);}
cs int N=15,SIZE=527,D=5e2+7;
using Int=std::vector<int>;
int B;
Int& operator++(Int &a){
if(!a.size())a.push_back(0);int b=1;
for(int re i=0;i<(int)a.size();++i)
if((a[i]+=b)>=B)a[i]-=B,b=1;else b=0;
if(b)a.push_back(b);return a;
}
Int& operator--(Int &a){
if(!a.size())a.push_back(0);a[0]-=1;
for(int re i=0;a[i]<0;++i)
a[i]+=B,a[i+1]--;
while(a.size()&&!a.back())a.pop_back();
return a;
}
Int gI(){
static int len;Int a;
static char s[1507];
static int num[1507];
scanf("%s",s);len=strlen(s);
for(int re i=0;i<len;++i)
num[len-i]=s[i]^48;
while(len){int t=0;
for(int re i=len;i;--i)
t=t*10+num[i],num[i]=t/B,t%=B;
a.push_back(t);
while(len&&!num[len])--len;
}return a;
}
Int &operator+=(Int &a,cs Int &b){
if(a.size()<b.size())a.resize(b.size());
for(int re i=0;i<(int)b.size();++i)a[i]+=b[i];
for(int re i=0;i+1<(int)a.size();++i)
if(a[i]>=B)a[i+1]++,a[i]-=B;
if(a.size())while(a.back()>=B){
int t=a.back();a.back()%=B;
a.push_back(t/B);
}return a;
}
int get_mod(cs Int &a){
int res=0;
for(int re i=a.size()-1;~i;--i)
Mul(res,B),Inc(res,a[i]);
return res;
}
int n,ans;
int good[D];
Int L[N],R[N],S;
int C[SIZE][D][N],Len;
int pr[SIZE][D][N],sf[SIZE][D][N];
int inv[N];
int G[N];
int F[2][2][N];
int calc(){
int t=0,s=1,Sl=S.size()-1;
memset(G,0,sizeof G);S.resize(Len);
memset(F[t],0,sizeof F[t]);F[t][1][0]=1;
for(int re i=0;i<Len;++i){
t^=1,s^=1;memset(F[t],0,sizeof F[t]);
for(int re x=0;x<n;++x){
if(!F[s][0][x]&&!F[s][1][x])continue;
int sm=add(F[s][0][x],F[s][1][x]);
int *pr=nullptr,*sf=nullptr,*C,*f0,*f1;
C=::C[i][S[i]],f0=F[t][0],f1=F[t][1];
if(S[i]-1>=0)pr=::pr[i][S[i]-1];
if(S[i]+1<B)sf=::sf[i][S[i]+1];
for(int re y=0;x+y<n;++y){
if(S[i]-1>=0)Inc(f0[x+y],mul(sm,pr[y]));
if(S[i]+1<B){
Inc(f1[x+y],mul(sm,sf[y]));
if(i>=Sl)
Inc(G[x+y],mul(sm,sf[y]));
}
Inc(f0[x+y],mul(F[s][0][x],C[y]));
Inc(f1[x+y],mul(F[s][1][x],C[y]));
if(i==Sl)
Inc(G[x+y],mul(F[s][1][x],C[y]));
}
}
}s=dec(0,get_mod(S));int res=0;
for(int i=0,c=1;i<n;++i){
if(i)Mul(c,mul(dec(s,i-1),inv[i]));
Inc(res,mul(G[n-1-i],c));
}return res;
}
void Main(){
scanf("%d%d",&n,&B);
for(int re i=0;i<B;++i)
scanf("%d",good+i);
for(int re i=0;i<n;++i)
L[i]=gI(),--L[i],R[i]=gI(),S+=R[i];
Len=S.size()+2;inv[0]=inv[1]=1;
for(int re i=2;i<n;++i)inv[i]=mul(mod-mod/i,inv[mod%i]);
for(int i=0,pw=1;i<Len;++i,Mul(pw,B)){
for(int re d=0;d<B;++d)
if(good[d]){
C[i][d][0]=1;for(int re j=1;j<n;++j)
C[i][d][j]=mul(mul(C[i][d][j-1],inv[j]),dec(mul(pw,d),j-1));
}
for(int re d=0;d<B;++d)for(int re j=0;j<n;++j)
pr[i][d][j]=add(d==0?0:pr[i][d-1][j],C[i][d][j]);
for(int re d=B-1;~d;--d)for(int re j=0;j<n;++j)
sf[i][d][j]=add(d==B-1?0:sf[i][d+1][j],C[i][d][j]);
}
for(int re s=0;s<(1<<n);++s){
S.clear();S.push_back(1);int ct=0;
for(int re i=0;i<n;++i)
(s&(1<<i))?(++ct,S+=R[i]):(S+=L[i]);
ct&1?Dec(ans,calc()):Inc(ans,calc());
}cout<<ans<<"\n";
}
inline void file(){
#ifdef zxyoi
freopen("A.in","r",stdin);
#endif
}signed main(){file();Main();return 0;}