题目描述

小皮球在计算出答案之后,买了一堆皮肤,他心里很开心,但是一不小心,就忘记自己买了哪些皮肤了。==|||万
幸的是,他还记得他把所有皮肤按照1~N来编号,他买来的那些皮肤的编号(他至少买了一款皮肤),最大公约数
是G,最小公倍数是L。现在,有Q组询问,每组询问输入一个数字X,请你告诉小皮球,有多少种合法的购买方案中
,购买了皮肤X?因为答案太大了,所以你只需要输出答案mod1000000007即可。

输入

第一行,三个数字N,G,L,如题意所示。
第二行,一个数字Q,表示询问个数。
第三行,Q个数字,表示每个询问所问的X。
N,G,L≤10^8,Q≤10^5,1≤X≤10^8

输出

对于每一组询问,在一行中单独输出一个整数,表示这个询问的答案。

样例输入

5 1 30
5
1 2 3 4 5

样例输出

1
2
2
0
2
 
将每个数质因数分解,那么$GCD$和$LCM$就分别是每个质因子的最小幂次的乘积和最大幂次的乘积。
一个不大于$10^8$的数最多有$8$个不同的质因子,可以考虑用状压来记录每个质因子的幂次的最大值和最小值是否达到了$GCD$和$LCM$的标准。
设$f[i][S1][S2]$表示前$i$个数的质因子的最小幂次是否达到的状态为$S1$,最大幂次是否达到的状态为$S2$时的方案数(为了方便,可以将$S1,S2$合并为一维)。
因为选取的数必须是$GCD$的倍数和$LCM$的约数,所以最多不会超过$600$个选取的数。
每次询问要指定必须选取某个数,我们记录前缀$DP$数组和后缀$DP$数组。
对于强制选取第$i$个数的情况,显然要将$i-1$的前缀$DP$数组和$i+1$的后缀$DP$数组合并,用或运算$FWT$合并即可。
那么对于合并后的$DP$数组,只要二进制状态是全集去掉第$i$个数的状态后的状态的父集就都合法,用与运算$FWT$正变换一下合并之后的$DP$数组即可。

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<cstdio>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int mod=1000000007;
const int inv=500000004;
bool vis[10010];
int prime[10010];
int cnt;
int G,L,Q;
int n,x;
int num;
int sum;
int mask;
int mx[10];
int pr[10];
int f[1<<16];
int g[1<<16];
int tmp[1<<16];
int p[1<<16];
int res[1<<16];
int pre[600][1<<16];
int suf[600][1<<16];
void find()
{
for(int i=2;i<=10000;i++)
{
if(!vis[i])
{
prime[++cnt]=i;
}
for(int j=1;j<=cnt&&prime[j]*i<=10000;j++)
{
vis[i*prime[j]]=1;
if(i%prime[j]==0)
{
break;
}
}
}
}
void FWT_OR(int *a,int len,int opt)
{
for(int k=2;k<=len;k<<=1)
{
int t=k>>1;
for(int i=0;i<len;i+=k)
{
for(int j=i;j<i+t;j++)
{
if(opt==1)
{
a[j+t]=(a[j+t]+a[j])%mod;
}
else
{
a[j+t]=(a[j+t]-a[j]+mod)%mod;
}
}
}
}
}
void FWT_AND(int *a,int len,int opt)
{
for(int k=2;k<=len;k<<=1)
{
int t=k>>1;
for(int i=0;i<len;i+=k)
{
for(int j=i;j<i+t;j++)
{
if(opt==1)
{
a[j]=(a[j]+a[j+t])%mod;
}
else
{
a[j]=(a[j]-a[j+t]+mod)%mod;
}
}
}
}
}
void take(int x)
{
for(int i=1;i<=cnt&&prime[i]*prime[i]<=x;i++)
{
if(x%prime[i]==0)
{
pr[++num]=prime[i];
while(x%prime[i]==0)
{
x/=prime[i];
mx[num]++;
}
}
}
if(x>1)
{
pr[++num]=x,mx[num]=1;
}
}
int quick(int x,int y)
{
int res=1;
while(y)
{
if(y&1)
{
res=1ll*res*x%mod;
}
y>>=1;
x=1ll*x*x%mod;
}
return res;
}
void dfs(int dep,int x,int S1,int S2)
{
if(dep>num)
{
res[S1|(S2<<num)]++;
return ;
}
for(int i=0;i<=mx[dep];i++)
{
dfs(dep+1,x,S1|((i==0)<<(dep-1)),S2|((i==mx[dep])<<(dep-1)));
if(1ll*x*pr[dep]>n)
{
return ;
}
x*=pr[dep];
}
}
void add(int &x,int y)
{
x+=y;
if(x>mod)
{
x-=mod;
}
}
int get(int x)
{
int S=0;
for(int i=1;i<=num;i++)
{
int ans=0;
while(x%pr[i]==0)
{
x/=pr[i],ans++;
}
if(!ans)
{
S|=1<<(i-1);
}
if(ans==mx[i])
{
S|=1<<(i-1+num);
}
}
return S;
}
int main()
{
scanf("%d%d%d%d",&n,&G,&L,&Q);
find();
if(L%G)
{
while(Q--)
{
puts("0");
}
return 0;
}
L/=G,n/=G;
take(L);
dfs(1,1,0,0);
mask=1<<(num+num);
for(int i=0;i<mask;i++)
{
if(res[i])
{
g[++sum]=i;
p[sum]=quick(2,res[i])-1;
}
}
f[0]=1,pre[0][0]=1;
for(int i=1;i<=sum;i++)
{
for(int j=0;j<mask;j++)
{
add(tmp[j|g[i]],1ll*f[j]*p[i]%mod);
}
for(int j=0;j<mask;j++)
{
add(f[j],tmp[j]),tmp[j]=0;
}
for(int j=0;j<mask;j++)
{
pre[i][j]=f[j];
}
}
memset(f,0,sizeof(f));
f[0]=1,suf[sum+1][0]=1;
for(int i=sum;i>=1;i--)
{
for(int j=0;j<mask;j++)
{
add(tmp[j|g[i]],1ll*f[j]*p[i]%mod);
}
for(int j=0;j<mask;j++)
{
add(f[j],tmp[j]),tmp[j]=0;
}
for(int j=0;j<mask;j++)
{
suf[i][j]=f[j];
}
}
for(int i=0;i<=sum;i++)
{
FWT_OR(pre[i],mask,1);
FWT_OR(suf[i+1],mask,1);
}
for(int i=0;i<sum;i++)
{
for(int j=0;j<mask;j++)
{
pre[i][j]=1ll*pre[i][j]*suf[i+2][j]%mod;
}
}
for(int i=0;i<sum;i++)
{
FWT_OR(pre[i],mask,-1);
FWT_AND(pre[i],mask,1);
}
while(Q--)
{
scanf("%d",&x);
if(x%G){puts("0");continue;}
x/=G;
if(L%x){puts("0");continue;}
if(x>n){puts("0");continue;}
int S=get(x);
int ans=0;
int y=lower_bound(g+1,g+1+sum,S)-g-1;
ans=pre[y][(mask-1)^S];
ans=1ll*ans*inv%mod*(p[y+1]+1)%mod;
printf("%d\n",ans);
}
}

BZOJ5019[Snoi2017]遗失的答案——FWT+状压DP的更多相关文章

  1. bzoj5019: [Snoi2017]遗失的答案

    Description 小皮球在计算出答案之后,买了一堆皮肤,他心里很开心,但是一不小心,就忘记自己买了哪些皮肤了.==|||万 幸的是,他还记得他把所有皮肤按照1-N来编号,他买来的那些皮肤的编号( ...

  2. BZOJ5019 SNOI2017遗失的答案(容斥原理)

    显然存在方案的数一定是L的因数,考虑对其因子预处理答案,O(1)回答. 考虑每个质因子,设其在g中有x个,l中有y个,则要求所有选中的数该质因子个数都在[x,y]中,且存在数的质因子个数为x.y.对于 ...

  3. 【BZOJ5019】[SNOI2017]遗失的答案(FWT,动态规划)

    [BZOJ5019][SNOI2017]遗失的答案(FWT,动态规划) 题面 BZOJ 题解 发现\(10^8\)最多分解为不超过\(8\)个本质不同质数的乘积. 而\(gcd\)和\(lcm\)分别 ...

  4. Luogu4221 WC2018州区划分(状压dp+FWT)

    合法条件为所有划分出的子图均不存在欧拉回路或不连通,也即至少存在一个度数为奇数的点或不连通.显然可以对每个点集预处理是否合法,然后就不用管这个奇怪的条件了. 考虑状压dp.设f[S]为S集合所有划分方 ...

  5. [WC2018]州区划分(状压DP+FWT/FMT)

    很裸的子集反演模板题,套上一些莫名其妙的外衣. 先预处理每个集合是否合法,再作显然的状压DP.然后发现可以写成子集反演的形式,直接套模板即可. 子集反演可以看这里. 子集反演的过程就是多设一维代表集合 ...

  6. bzoj 5019 [Snoi2017]遗失的答案

    题面 https://www.lydsy.com/JudgeOnline/problem.php?id=5019 题解 如果L不是G的倍数 答案为0 下面考虑G|L的情况 将G,L质因数分解 设$L= ...

  7. 洛谷$P5366\ [SNOI2017]$遗失的答案 数论+$dp$

    正解:数论$dp$ 解题报告: 传送门$QwQ$ 考虑先质因数分解.所以$G$就相当于所有系数取$min$,$L$就相当于所有系数取$max$ 这时候考虑,因为数据范围是$1e8$,$1e8$内最多有 ...

  8. [NOIP2016]愤怒的小鸟 D2 T3 状压DP

    [NOIP2016]愤怒的小鸟 D2 T3 Description Kiana最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于(0,0)处,每次Kiana可 ...

  9. bzoj3380: [Usaco2004 Open]Cave Cows 1 洞穴里的牛之一(spfa+状压DP)

    数据最多14个有宝藏的地方,所以可以想到用状压dp 可以先预处理出每个i到j的路径中最小权值的最大值dis[i][j] 本来想用Floyd写,无奈太弱调不出来..后来改用spfa 然后进行dp,这基本 ...

随机推荐

  1. Less与TypeScript的简单理解与应用,并使用WebPack打包静态页面

    既然选择了远方,便只顾风雨兼程 __ HANS许 系列:零基础搭建前后端分离项目 系列:零基础搭建前后端分离项目 创建空项目 使用Less 使用TypeScript 使用WebPack 开始写项目 总 ...

  2. 回顾曾经的自己,献给java初学者的建议

    要不惜代价投资自己,任何对自己的投资都是值得的 要多学习数据结构, 习惯看源码! 一份知识经过n个人的传递早已经不成样子了 遇到问题不要直接百度,百度上那些花里胡哨的东西有用的很少,对症下药才是王道, ...

  3. OO第二单元总结

    这一单元作业是围绕电梯调度进行展开,并引进了多线程的概念.与第一次作业比较类似,作业难度也是逐渐推进,从最开始的单部电梯先来先服务(傻瓜式调度),到之后的单部电梯可稍带调度,到最后的多部电梯分楼层调度 ...

  4. 折腾Java设计模式之访问者模式

    博客原文地址:折腾Java设计模式之访问者模式 访问者模式 Represent an operation to be performed on the elements of an object st ...

  5. 智能指针std::weak_ptr

    std::weak_ptr 避免shared_ptr内存泄漏的利器.

  6. git错误--ssh: Could not resolve hostname ssh.github.com: Name or service not known--解决方式

    错误如下: git push origin ssh: Could not resolve hostname ssh.github.com: Name or service not known fata ...

  7. VSCode 下载Models 报错

    VSCode调试部分代码时,报错,提示不能自动获取Models.报错信息如下. go: golang.org/x/crypto@v0.-80db560fac1f: unrecognized impor ...

  8. Python之python的一些理解

    应用领域: 1. 网络爬虫 2. 大数据分析与挖掘 3. 机器学习 4. web应用 5. 游戏开发 6. 自动化运维 入门学习网站: imooc,廖雪峰,黑马 环境变量 --- 就是告诉电脑,你的程 ...

  9. 导入python库失败时的方法

    出现以下错误如何解决: e.g. cmd:   pip install Django -i  http://mirrors.aliyun.com/pypi/simple/ --trusted-host ...

  10. c++11の关联容器

    一.关联容器 C++的容器类型可以分为顺序容器和关联容器两大类.对于关联容器,主要有map和set,对于这两种,根据不同的维度,衍生出了8种容器 map                        ...