【BZOJ5019】[SNOI2017]遗失的答案(FWT,动态规划)
【BZOJ5019】[SNOI2017]遗失的答案(FWT,动态规划)
题面
题解
发现\(10^8\)最多分解为不超过\(8\)个本质不同质数的乘积。
而\(gcd\)和\(lcm\)分别就是每个质因子的最大次幂和最小次幂的乘积。
那么考虑一个状压\(dp\),设\(f[S1][S2]\)表示最小/最大次幂是否被取到的方案数。
而能够被统计入答案的数一定是在\(gcd\)和\(lcm\)之间的数,并且是\(gcd\)的倍数,\(lcm\)的因数。
直接爆搜,这样的数不会太多。然后可以把他们归类,按照他们能够取到最大最小次幂归类,这样子的状态不会超过\(600\)。
然后考虑\(dp\)的转移,十分显然,现在的问题在于有一个必定选,这个如何考虑。
那么我们存下前缀后缀的\(dp\)结果,那么合并的答案显然是两者做或卷积,直接\(FWT\)实现即可。
那么考虑这个数的贡献,也就是全集异或上这个数最大最小次幂状态的超集。那么把预处理的前后或卷积再做一个超集和,这样子就是可以做到单次\(O(1)\)回答。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MOD 1000000007
#define inv2 500000004
void add(int &x,int y){x+=y;if(x>MOD)x-=MOD;}
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
const int MP=10000;
int pri[MP+10],tot;
bool zs[MP+10];
void Pre(int n)
{
for(int i=2;i<=n;++i)
{
if(!zs[i])pri[++tot]=i;
for(int j=1;j<=tot&&i*pri[j]<=n;++j)
{
zs[i*pri[j]]=true;
if(i%pri[j]==0)break;
}
}
}
int n,G,L,Q,ans;
int p[50],mx[50],mn[50],num,qwq=1;
void fj(int x)
{
for(int i=1;i<=tot&&pri[i]*pri[i]<=x;++i)
if(x%pri[i]==0)
{
p[++num]=pri[i];
while(x%pri[i]==0)x/=pri[i],++mx[num];
}
if(x>1)p[++num]=x,mx[num]=1;
}
int cnt[1<<16];
void dfs(int x,int s,int S1,int S2)
{
if(x==num+1){cnt[S1|(S2<<num)]+=1;return;}
for(int i=0;i<=mx[x];++i)
{
dfs(x+1,s,S1|((i==0)<<(x-1)),S2|((i==mx[x])<<(x-1)));
if(1ll*s*p[x]>n)return;
s*=p[x];
}
}
int fpow(int a,int b)
{
int s=1;
while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}
return s;
}
int get(int x)
{
int S=0;
for(int i=1;i<=num;++i)
{
int cnt=0;
while(x%p[i]==0)x/=p[i],++cnt;
if(cnt==0)S|=1<<(i-1);
if(cnt==mx[i])S|=1<<(i-1+num);
}
return S;
}
int f[1<<16],tmp[1<<16],gnt[1<<16];
int zt[1<<16],T;
int pre[600][1<<16],suf[600][1<<16];
void FWT(int *a,int N,int opt)
{
for(int i=1;i<N;i<<=1)
for(int p=i<<1,j=0;j<N;j+=p)
for(int k=0;k<i;++k)
if(opt==1)a[i+j+k]=(a[j+k]+a[i+j+k])%MOD;
else a[i+j+k]=(a[i+j+k]+MOD-a[j+k])%MOD;
}
void FWT_and(int *a,int N,int opt)
{
for(int i=1;i<N;i<<=1)
for(int p=i<<1,j=0;j<N;j+=p)
for(int k=0;k<i;++k)
if(opt==1)a[j+k]=(a[j+k]+a[i+j+k])%MOD;
else a[j+k]=(a[j+k]+MOD-a[i+j+k])%MOD;
}
int main()
{
n=read();G=read();L=read();Q=read();Pre(10000);
if(L%G){while(Q--)puts("0");return 0;}
L/=G;n/=G;fj(L);dfs(1,1,0,0);int SS=1<<(num+num);
for(int i=0;i<SS;++i)
if(cnt[i])zt[++T]=i,gnt[T]=fpow(2,cnt[i])-1;
for(int i=1;i<=T;++i)cnt[i]=gnt[i];
f[0]=1;pre[0][0]=1;
for(int x=1;x<=T;++x)
{
int i=zt[x];
for(int j=0;j<SS;++j)
add(tmp[j|i],1ll*f[j]*cnt[x]%MOD);
for(int j=0;j<SS;++j)add(f[j],tmp[j]),tmp[j]=0;
for(int j=0;j<SS;++j)pre[x][j]=f[j];
}
memset(f,0,sizeof(f));
f[0]=1;suf[T+1][0]=1;
for(int x=T;x;--x)
{
int i=zt[x];
for(int j=0;j<SS;++j)
add(tmp[j|i],1ll*f[j]*cnt[x]%MOD);
for(int j=0;j<SS;++j)add(f[j],tmp[j]),tmp[j]=0;
for(int j=0;j<SS;++j)suf[x][j]=f[j];
}
for(int i=0;i<=T;++i)FWT(pre[i],SS,1);
for(int i=1;i<=T+1;++i)FWT(suf[i],SS,1);
for(int i=0;i<=T;++i)
for(int j=0;j<SS;++j)
pre[i][j]=1ll*pre[i][j]*suf[i+2][j]%MOD;
for(int i=0;i<=T;++i)FWT(pre[i],SS,-1),FWT_and(pre[i],SS,1);
while(Q--)
{
int x=read();
if(x%G){puts("0");continue;}x/=G;
if(L%x){puts("0");continue;}
if(x>n){puts("0");continue;}
int d=get(x),ans=0;
int p=lower_bound(&zt[1],&zt[T+1],d)-zt-1;
ans=pre[p][(SS-1)^d];
ans=1ll*ans*(cnt[p+1]+1)%MOD*inv2%MOD;
printf("%d\n",ans);
}
}
【BZOJ5019】[SNOI2017]遗失的答案(FWT,动态规划)的更多相关文章
- BZOJ5019[Snoi2017]遗失的答案——FWT+状压DP
题目描述 小皮球在计算出答案之后,买了一堆皮肤,他心里很开心,但是一不小心,就忘记自己买了哪些皮肤了.==|||万 幸的是,他还记得他把所有皮肤按照1-N来编号,他买来的那些皮肤的编号(他至少买了一款 ...
- BZOJ5019 SNOI2017遗失的答案(容斥原理)
显然存在方案的数一定是L的因数,考虑对其因子预处理答案,O(1)回答. 考虑每个质因子,设其在g中有x个,l中有y个,则要求所有选中的数该质因子个数都在[x,y]中,且存在数的质因子个数为x.y.对于 ...
- bzoj5019: [Snoi2017]遗失的答案
Description 小皮球在计算出答案之后,买了一堆皮肤,他心里很开心,但是一不小心,就忘记自己买了哪些皮肤了.==|||万 幸的是,他还记得他把所有皮肤按照1-N来编号,他买来的那些皮肤的编号( ...
- bzoj 5019: [Snoi2017]遗失的答案【dp+FWT】
满足GL的组合一定包含GL每个质因数最大次幂个最小次幂,并且能做限制这些数不会超过600个 然后质因数最多8个,所以可以状压f[s1][s2]为选s1集合满足最大限制选s2集合满足最小限制 dfs一下 ...
- bzoj 5019 [Snoi2017]遗失的答案
题面 https://www.lydsy.com/JudgeOnline/problem.php?id=5019 题解 如果L不是G的倍数 答案为0 下面考虑G|L的情况 将G,L质因数分解 设$L= ...
- LOJ2257 SNOI2017 遗失的答案 容斥、高维前缀和
传送门 数字最小公倍数为\(L\)的充分条件是所有数都是\(L\)的约数,而\(10^8\)内最多约数的数的约数也只有\(768\)个.所以我们先暴力找到所有满足是\(L\)的约数.\(G\)的倍数的 ...
- luogu P5366 [SNOI2017]遗失的答案
luogu 首先gcd为\(G\),lcm为\(L\),有可能出现的数(指同时是\(G\)的因数以及是\(L\)的倍数)可以发现只有几百个.如果选出的数要能取到gcd,那么对于每种质因子,都要有一个数 ...
- [SNOI2017]遗失的答案
题目 首先\(G,L\)肯定会满足\(G|L\),否则直接全部输出\(0\) 之后我们考虑一下能用到的质因数最多只有\(8\)个 同时我们能选择的数\(x\)肯定是\(L\)的约数,还得是\(G\)的 ...
- 洛谷$P5366\ [SNOI2017]$遗失的答案 数论+$dp$
正解:数论$dp$ 解题报告: 传送门$QwQ$ 考虑先质因数分解.所以$G$就相当于所有系数取$min$,$L$就相当于所有系数取$max$ 这时候考虑,因为数据范围是$1e8$,$1e8$内最多有 ...
随机推荐
- LiveCharts文档-3开始-7标签
原文:LiveCharts文档-3开始-7标签 LiveCharts文档-3开始-7标签 Label就是Chart中表示数值的字符串,通常被放置在轴的位置和提示当中. 下图中的这些字符串显示的都是标签 ...
- Codeforces 996E Leaving the Bar (随机化)
题目连接:Leaving the Bar 题意:给你n个向量,你可以加这个向量或减这个向量,使得这些向量之和的长度小于1.5e6. 题解: 按照正常的贪心方法,最后的结果有可能大于1.5e6 .这里我 ...
- item 6: 当auto推导出一个不想要的类型时,使用显式类型初始化的语法
本文翻译自<effective modern C++>,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 Item 5解释了比起显式指定类型,使用auto来 ...
- ExtJS初探:在项目中使用ExtJS
注意:本文写作时间是 2013 年,所讲的 ExtJS 如今早已过时,请勿学习! -------------------------------- 今天ExtJS官网发布了ExtJS最新正式版4.2. ...
- Mac下通过VMware Fusion安装centos虚拟机操作记录
下面介绍下利用VMware Fusion工具在Mac上安装centos虚拟机的做法:1)下载VMware Fusion工具下载地址(包括注册码):http://www.macx.cn/thread-2 ...
- PairWork-电梯调度程序结对编程【附加题】
1 接口改进 1) 之前判断电梯是否闲置的函数不太好理解,重新修改了,如下所示: //是否停顿状态(停止的以及开门间隔>=0) public bool IsIdle { get { return ...
- 个人博客作业-Week7
团队任务中个人感想 我们团队选的题目是爬虫, 采用用AVA平台开发了, 我原来JAVA语言不熟悉了, PM考虑这部分之后分配任务这部分感觉很多谢 团队当中的PM很清楚每个组员的力量, 所以PM跟每个组 ...
- Week 3 结对编程
Group: 杜正远 潘礼鹏 结对编程: 优点: 集体荣誉感.你们已经是一个集体了,一定得为对方着想负责. 1.看对方的代码,彼此会互相学习到一些奇妙的方法. 2.结对编程能把两个事情分开,降低复杂度 ...
- DWR实现服务器向客户端推送消息
原文链接 http://www.blogjava.net/stevenjohn/archive/2012/07/07/382447.html这片文章还是给了我很大帮助,再次表示感谢,下面我将这两天的研 ...
- SVN解决冲突
SVN冲突出现场景 如今是一个团结协作的时代,开发一个系统,往往会多人协作共同完成.版本管理是必不可少的,常用的软件有Git,SVN等.今天说一下,SVN管理版本时,如果出现冲突后,如何快速解决冲突. ...