前言
这题一开始觉得很难写。。
实际上如果你先把暴力写好,再修改,还是蛮好写的
写了不到2h就写过了。。
题解
我们可以吧
L
和
显然,不同的质因数最多只有8个
然后设一个质因数i,他在
L
里面的次数是a,在
那么他选的数,对于i的次数,只能是a到b之间
那么就是说可行的数是可以预先找出来的
然后有一个结论(可以打表证明),可行的数,不超过1000个
然后你想把可行的数都找出来
然后你现在要在里面找一些数满足条件:对于一个质因数i,必须至少有一个数,使得i在他里面的次数是a。然后至少有一个数,使得i在他里面的次数是b
问你有多少种方案
其实就相当于有
2∗8
个限制,要你满足
然后这个就可以容斥了
怎么容斥就自己想想就好了。。
CODE:
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<bitset>
using namespace std;
typedef long long LL;
const int MOD=1000000007;
const int N=100005;
const int K=1005;
const int M=20;
int n,g,l;//1~n 最大公约数是g,最小公倍数是l
int pri[N],tot=0;
int a[N],b[N];//两个东西分别有多少个
int c[K],lalal=0;//有哪些数是合法的
int t[M],h[M];//这个质数的两个边界
LL pow (int x,LL y)
{
if (y<0) return 0;
if (y==0) return 1;
if (y==1) return x;
LL lalal=pow(x,y>>1);
lalal=lalal*lalal%MOD;
if (y&1) lalal=lalal*x%MOD;
return lalal;
}
void prepare ()
{
int L=l,G=g;
for (int u=2;u*u<=L;u++)
if (L%u==0)
{
pri[++tot]=u;
while (L%u==0) {a[tot]++;L/=u;}
}
if (L!=1) {pri[++tot]=L;a[tot]=1;}
for (int u=1;u<=tot;u++)
while (G%pri[u]==0)
{G/=pri[u];b[u]++;}
for (int u=1;u<=tot;u++)
{
int shen=1;
for (int i=1;i<=b[u];i++) shen=shen*pri[u];
t[u]=shen;
for (int i=b[u]+1;i<=a[u];i++) shen=shen*pri[u];
h[u]=shen;
}
}
void dfs (int x,int y)//选到第几个因数 当前的值是什么
{
if (y>n) return ;
if (x>tot) {c[++lalal]=y;return ;}
int shen=1;
for (int u=1;u<=b[x];u++) shen=shen*pri[x];
for (int u=b[x];u<=a[x];u++)
{
dfs(x+1,y*shen);
shen=shen*pri[x];
}
}
LL ans[K];
void find (int x)
{
int l=1,r=lalal;
while (l<=r)
{
int mid=(l+r)>>1;
if (c[mid]==x) {printf("%lld\n",ans[mid]);return ;}
if (c[mid]>x) r=mid-1;
if (c[mid]<x) l=mid+1;
}
printf("0\n");
return ;
}
bool ok[N];//这个数还在不在考虑范围内
bitset<K> s[1<<20];
LL o[1<<20];//有多少个
void dfs2 (int x,int y,int z,int v)//我们现在处理到第几个条件 要更新的是哪一个 当前已经有多少个至少是不满足的
{
if (x>2*tot)
{
if (s[z][y]==false) return ;
if ((2*tot-v)%2==0) ans[y]=(ans[y]+o[z])%MOD;
else ans[y]=((ans[y]-o[z])%MOD+MOD)%MOD;
return ;
}
dfs2(x+1,y,z<<1,v);
dfs2(x+1,y,(z<<1)+1,v+1);
}
void dfs1 (int x,int z)
{
if (x>2*tot)
{
for (int u=1;u<=lalal;u++) s[z][u]=true;
for (int u=1;u<=tot;u++)
if ((z&(1<<u-1))!=0)//如果这个条件是不满足的
for (int i=1;i<=lalal;i++)
if ((c[i]/t[u])%pri[u]!=0)//如果这个是有底线的
s[z][i]=false;
for (int u=tot+1;u<=tot*2;u++)
if ((z&(1<<u-1))!=0)//如果这个条件是不满足的
for (int i=1;i<=lalal;i++)
if (c[i]%h[u-tot]==0)//如果这个是有顶线的
s[z][i]=false;
for (int u=1;u<=lalal;u++)
if (s[z][u]==true)
o[z]++;
o[z]=pow(2,o[z]-1);
return ;
}
dfs1(x+1,z<<1);
dfs1(x+1,(z<<1)+1);
}
int main()
{
scanf("%d%d%d",&n,&g,&l);
if (l%g!=0)
{
int q;
scanf("%d",&q);
while (q--) printf("0\n");
return 0;
}
prepare();
dfs(1,1);
sort(c+1,c+1+lalal);
dfs1(1,0);
for (int u=1;u<=lalal;u++)
dfs2(1,u,0,0);
int q;
scanf("%d",&q);
while (q--)
{
int x;
scanf("%d",&x);
find(x);
}
return 0;
}