题目描述

小皮球在计算出答案之后,买了一堆皮肤,他心里很开心,但是一不小心,就忘记自己买了哪些皮肤了。==|||万
幸的是,他还记得他把所有皮肤按照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. Lumen框架—升级改造之路-开篇

    一.前言    首先,我先阐述下,为什么要做这件事.lumen是一款比较轻型的PHP框架,但是,作为项目开发来说,它还是缺少很多东西,比如Response返回值规范的自定义,异常抛出格式的自定义,以及 ...

  2. AppStore IPv6-only审核被拒原因分析及解决方案-a

    Apple关于IPV6规定 日前,苹果公司向开发者发出提醒,公司将会修改应用商店App Store的相关规定,所有IOS应用必须包含对IPv6-only标准的支持.据悉,该规定在6月1日生效,所有提交 ...

  3. 学JAVA第十七天,接口与抽象方法

    JAVA接口可以让代码更加有合理的规范性,就想一个项目小组,组长要负责把成员的代码整合,但是每个成员写的方式都是按照他们自己的想法来写的, 所以,整合起来就非常麻烦. 但是,如果我们的组长制作了一个接 ...

  4. 关于单链表的增删改查方法的递归实现(JAVA语言实现)

    因为在学习数据结构,准备把java的集合框架底层源码,好好的过一遍,所以先按照自己的想法把单链表的类给写出来了; 写该类的目的: 1.练习递归 2.为深入理解java集合框架底层源码打好基础 学习的视 ...

  5. oracle学习笔记(五) SQL操作符

    SQL操作符 算术操作符:+加,-减,*乘,/除 比较操作符: <,>,=,!=,<>,<=,>= 常用的判断,<>和!=相同 between $low ...

  6. Django 提交 form 表单

    创建 Django 的过程可以参考上一篇文章 https://www.cnblogs.com/klvchen/p/10601536.html 在 templates 文件夹下创建一个 index.ht ...

  7. 44.Odoo产品分析 (五) – 定制板块(1) – 管理odoo安装(1)

    查看Odoo产品分析系列--目录 1 管理员的注意事项 在记录重要的配置细节时必须要小心,而且必须要有一个连续性的合适的.让系统能够安装备份并运行在一个可接受的时间内的计划. 1.1 制定实施策略 如 ...

  8. MyBatis学习---整合SpringMVC

    [目录]

  9. Git - git tag - 查看当前分支 tag 版本&说明

    索引: 目录索引 参看代码 GitHub: git.txt 一.示例: git tag -l -n 二.说明: 1."tag" 部分 tag 代表的是标签动作,可以带参数 ,也可以 ...

  10. leetcode题解-122买卖股票的最佳时期

    题目 leetcode题解-122.买卖股票的最佳时机:https://www.yanbinghu.com/2019/03/14/30893.html 题目详情 给定一个数组,它的第 i 个元素是一支 ...