题意:设$f(n,k)=\sum\limits_{\substack{S\subseteq\{1,\cdots,n\}\\|S|=k}}\prod\limits_{x\in S}x$,问$f(n,0\cdots n)$中有多少个数无法被$p$整除
首先注意到$f(n,k)=[x^{n-k}]\prod\limits_{i=1}^n(x+i)$,所以我们就是要求$P(x)=\prod\limits_{i=1}^n(x+i)$在模$p$意义下有多少项
先分类,设$c=\left\lfloor\frac np\right\rfloor,f(x)=\prod\limits_{i=1}^p(x+i),g(x)=\prod\limits_{i=1}^{n\%p}(x+i)$,那么$P(x)=f^c(x)g(x)$
然后我们有$f(x)\equiv x^p-x(\bmod p)$,证明暂时咕咕咕...这是显然的,因为两边都在模$p$意义下有$p$个根
因为我们要求它有多少项,所以把$f(x)$换成$x^{p-1}-1$是没问题的,为了方便,如果$n\%p=p-1$,我们令$c=\left\lfloor\frac np\right\rfloor+1,g(x)=1$
因为$f^c(x)=\sum\limits_{i=0}^c\binom cix^{i(p-1)}(-1)^{c-i}$只含$x^{i(p-1)}$项且$\deg(g)\lt p-1$,所以它们每一项两两相乘得到的指数不同,也就是说我们只需求出$f^c(x)$和$g(x)$的项数,再相乘即可
对于$f^c(x)$,主要是看$\binom ci$是否被$p$整除,如果把$c$和$i$都写成$p$进制数,根据Lucas定理,仅当$c$的每一位都$\geq i$时$\binom ci\equiv0(\bmod p)$,所以把$c$写成$p$进制数$c_1\cdots c_k$,方案数就是$\prod\limits_{i=1}^k(c_i+1)$
对于$g(x)$,直接分治FFT即可
总时间复杂度$O\left(\log^2n+p\log^2p\right)$
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef double du;
const du pi=3.141592653589793238462643383;
const int mod=1000000007;
int mul(int a,int b){return a*(ll)b%mod;}
struct comp{
du x,y;
comp(du a=0,du b=0){x=a;y=b;}
};
comp operator+(comp a,comp b){return comp(a.x+b.x,a.y+b.y);}
comp operator-(comp a,comp b){return comp(a.x-b.x,a.y-b.y);}
comp operator*(comp a,comp b){return comp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
int rev[131072],N;
comp w[17][131072];
void pre(int n){
int i,j,k;
for(N=1,k=0;N<n;N<<=1)k++;
for(i=0;i<N;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
for(i=2,k=0;i<=N;i<<=1,k++){
for(j=0;j<i>>1;j++)w[k][j]=comp(cos(j*pi/(i/2)),sin(j*pi/(i/2)));
}
}
void fft(comp*a,int on){
int i,j,k,f;
comp t;
for(i=0;i<N;i++){
if(i<rev[i])swap(a[i],a[rev[i]]);
}
for(f=0,i=2;i<=N;i<<=1,f++){
for(j=0;j<N;j+=i){
for(k=0;k<i>>1;k++){
t=w[f][k];
if(on==-1)t.y=-t.y;
t=t*a[i/2+j+k];
a[i/2+j+k]=a[j+k]-t;
a[j+k]=a[j+k]+t;
}
}
}
if(on==-1){
for(i=0;i<N;i++)a[i].x/=N;
}
}
comp t1[131072],t2[131072];
int p;
void conv(int*a,int n,int*b,int m,int*c){
int i;
pre(n+m);
memset(t1,0,N<<4);
memset(t2,0,N<<4);
for(i=0;i<n;i++)t1[i]=a[i];
for(i=0;i<m;i++)t2[i]=b[i];
fft(t1,1);
fft(t2,1);
for(i=0;i<N;i++)t1[i]=t1[i]*t2[i];
fft(t1,-1);
for(i=0;i<n+m-1;i++)c[i]=llround(t1[i].x)%p;
}
char s[510];
int num[510],pnum[2010],len,pn;
bool div(){
int i,t=0;
bool f=0;
for(i=len;i>0;i--){
t=t*10+num[i];
num[i]=0;
if(t>=p){
num[i]=t/p;
t%=p;
}
if(num[i])f=1;
}
pnum[pn++]=t;
return f;
}
int*solve(int l,int r){
int mid=(l+r)>>1,*s,*ls,*rs;
s=new int[r-l+2];
if(l==r){
s[1]=1;
s[0]=l;
return s;
}
ls=solve(l,mid);
rs=solve(mid+1,r);
conv(ls,mid-l+2,rs,r-mid+1,s);
return s;
}
void work(){
int i,n,df,dg,*a;
scanf("%s%d",s,&p);
len=strlen(s);
for(i=0;i<len;i++)num[len-i]=s[i]-'0';
pn=0;
while(div());
pnum[pn]=0;
if(pnum[0]==0)
dg=1;
else if(pnum[0]==p-1){
dg=1;
pnum[1]++;
for(i=1;i<pn&&pnum[i]==p;i++){
pnum[i]=0;
pnum[i+1]++;
}
}else{
n=pnum[0];
a=solve(1,n);
dg=0;
for(i=0;i<=n;i++)dg+=(a[i]!=0);
}
df=1;
for(i=1;i<=pn;i++)df=mul(df,pnum[i]+1);
printf("%d\n",(mul(df,dg)+mod)%mod);
}
int main(){
int T;
scanf("%d",&T);
while(T--)work();
}