题目:https://www.luogu.org/problemnew/show/P1072
思路是把每个数质因数分解,答案对于每个质因数的次数有选择的区间,通过这个计算。
指数的限制就是上限是b1,下限是a1;a0-a1后有剩余的自己不能有;b1-b0有剩余的自己不能剩(即必须满上限)。
分解质因数用了那个好像是 O( n^(1/4) ) 的方法。其实如果给的都是大质数是不是会被卡?
然后写了无比冗长的代码。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=35; int T,a0,a1,b0,b1,p[N],tot,hi[N],lo[N],hi2[N],lo2[N],lm[N],ans; bool flag=0; int rdn() { int ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='0'&&ch<='9') ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); return fx?ret:-ret; } int main() { T=rdn(); while(T--) { a0=rdn(); a1=rdn(); b0=rdn(); b1=rdn(); int n=b1; tot=0;//limit for(int i=2;i*i<=n;i++) { if(n%i==0) { p[++tot]=i;lo[tot]=hi[tot]=lo2[tot]=hi2[tot]=0; while(n%i==0)n/=i,hi[tot]++; hi2[tot]=hi[tot]; } } if(n>1) { p[++tot]=n;lo[tot]=hi[tot]=lo2[tot]=hi2[tot]=0; hi[tot]=hi2[tot]=1; } flag=0; n=a1; int p0=1;//bottom for(int i=2;i*i<=n;i++) if(n%i==0) { int d=0; while(n%i==0)n/=i,d++; while(p0<tot&&p[p0]<i)p0++; if(p[p0]!=i){flag=1;break;} lo[p0]=d; } if(flag){puts("0");continue;} if(n>1) { while(p0<tot&&p[p0]<n)p0++; if(p[p0]==n) lo[p0]=1; } flag=0; for(int i=1;i<=tot;i++)if(hi[i]<lo[i]){flag=1;break;} if(flag){puts("0");continue;} n=b0; p0=1; for(int i=2;i*i<=n;i++) { if(n%i==0) { int d=0; while(n%i==0)n/=i,d++; while(p0<tot&&p[p0]<i)p0++; if(p[p0]!=i)continue; lo2[p0]=d;//can't leave } } if(n>1) { while(p0<tot&&p[p0]<n)p0++; if(p[p0]==n) lo2[p0]=1; } for(int i=1;i<=tot;i++) { int d=hi[i]-lo2[i]; if(d) lo2[i]=hi[i]; else lo2[i]=0; } n=a0; p0=1; for(int i=2;i*i<=n;i++) { if(n%i==0) { int d=0; while(n%i==0)n/=i,d++; while(p0<tot&&p[p0]<i)p0++; if(p[p0]!=i)continue; if(d>lo[p0])hi2[p0]=lo[p0];//can't exist } } if(n>1) { while(p0<tot&&p[p0]<n)p0++; if(p[p0]==n) if(1>lo[p0])hi2[p0]=lo[p0]; } for(int i=1;i<=tot;i++) hi[i]=min(hi[i],hi2[i]),lo[i]=max(lo[i],lo2[i]); ans=1; flag=1; for(int i=1;i<=tot;i++) { if(lo[i]>hi[i]){flag=0;break;} ans*=hi[i]-lo[i]+1; } printf("%d ",flag?ans:0); } return 0; }