bzoj 5019: [Snoi2017]遗失的答案【dp+FWT】
满足GL的组合一定包含GL每个质因数最大次幂个最小次幂,并且能做限制这些数不会超过600个
然后质因数最多8个,所以可以状压f[s1][s2]为选s1集合满足最大限制选s2集合满足最小限制
dfs一下预处理出质因数只选一个质因数的初始状态
然后dp,做一个前缀一个后缀,设f[i][j]为前i个质因数选成集合j的方案数,g[i][j]为后i个质因数选成集合j的方案数,然后转移很好想,就是f[i][va[i]|j]+=f[i-1][j]*rs[i],其中rs是满足第i个质因数的方案数,g同理
然后我们需要合并出来一个“空出一个数”这样的东西来回答询问,合并的时候用orFWT即可
包含集合s的方案数也加到s的方案数里,就是andFWT的正变换部分,这样统计答案的时候就不用跑一遍了
然后回答的时候就是统计一下x极大极小质因数次幂的贡献然后直接查空出来这个集合的部分,最后乘上这个集合的选区方案数即可
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=100005,mod=1000000007,inv2=500000004;
int n,G,L,q,lm,p[N],tot,si[N],s[N],rs[N],va[N],con,f[605][70005],g[605][70005];
bool v[N];
int read()
{
int r=0,f=1;
char p=getchar();
while(p>'9'||p<'0')
{
if(p=='-')
f=-1;
p=getchar();
}
while(p>='0'&&p<='9')
{
r=r*10+p-48;
p=getchar();
}
return r*f;
}
void jia(int &x,int y)
{
x+=y;
(x>=mod)?x-=mod:0;
}
void jian(int &x,int y)
{
x-=y;
(x<0)?x+=mod:0;
}
void dfs(int w,long long v,int s1,int s2)
{
if(w==tot+1)
{
s[s1|(s2<<tot)]++;
return;
}
for(int i=0;i<=si[w];i++)
{
dfs(w+1,v,s1|((i==0)<<(w-1)),s2|((i==si[w])<<(w-1)));
v*=p[w];
if(v>n)
break;
}
}
int ksm(int a,int b)
{
int r=1;
while(b)
{
if(b&1)
r=1ll*r*a%mod;
a=1ll*a*a%mod;
b>>=1;
}
return r;
}
void fwtor(int a[],int f)
{
for(int i=1;i<lm;i<<=1)
for(int j=0;j<lm;j+=(i<<1))
for(int k=0;k<i;k++)
{
if(f==1)
jia(a[i+j+k],a[j+k]);
else
jian(a[i+j+k],a[j+k]);
}
}
void fwtand(int a[],int f)
{
for(int i=1;i<lm;i<<=1)
for(int j=0;j<lm;j+=(i<<1))
for(int k=0;k<i;k++)
{
if(f==1)
jia(a[j+k],a[i+j+k]);
else
jian(a[j+k],a[i+j+k]);
}
}
int main()
{
n=read(),G=read(),L=read(),q=read();
if(L%G)
{
while(q--)
puts("0");
return 0;
}
L/=G,n/=G;
int x=L;
for(int i=2;i*i<=L;i++)
if(x%i==0)
{
p[++tot]=i;
while(x%i==0)
si[tot]++,x/=i;
}
if(x>1)
p[++tot]=x,si[tot]=1;
dfs(1,1,0,0);
int ss=(1<<(tot*2));
for(int i=0;i<ss;i++)
if(s[i])
va[++con]=i,rs[con]=ksm(2,s[i])-1;
f[0][0]=1;
for(int i=1;i<=con;i++)
{
for(int j=0;j<ss;j++)
jia(f[i][va[i]|j],1ll*f[i-1][j]*rs[i]%mod);
for(int j=0;j<ss;j++)
jia(f[i][j],f[i-1][j]);
}
g[con+1][0]=1;
for(int i=con;i>=1;i--)
{
for(int j=0;j<ss;j++)
jia(g[i][va[i]|j],1ll*g[i+1][j]*rs[i]%mod);
for(int j=0;j<ss;j++)
jia(g[i][j],g[i+1][j]);
}
lm=ss;
for(int i=0;i<=con;i++)
fwtor(f[i],1);
for(int i=1;i<=con+1;i++)
fwtor(g[i],1);
for(int i=0;i<=con;i++)
for(int j=0;j<ss;j++)
f[i][j]=1ll*f[i][j]*g[i+2][j]%mod;
for(int i=0;i<=con;i++)
fwtor(f[i],-1),fwtand(f[i],1);
// for(int i=0;i<=con;i++)
// {
// for(int j=0;j<ss;j++)
// cerr<<f[i][j]<<" ";
// cerr<<endl;
// }
while(q--)
{
int x=read(),s=0;
if(x%G||L%(x/G)||(x/G)>n)
{
puts("0");
continue;
}
x/=G;
for(int i=1;i<=tot;i++)
{
int sm=0;
while(x%p[i]==0)
x/=p[i],sm++;
if(sm==0)
s|=(1<<(i-1));
if(sm==si[i])
s|=(1<<(i-1+tot));
}
int w=lower_bound(&va[1],&va[con+1],s)-va-1;//cerr<<w<<endl;
printf("%lld\n",((1ll*f[w][(ss-1)^s]*(rs[w+1]+1)%mod*inv2%mod)+mod)%mod);
}
return 0;
}
bzoj 5019: [Snoi2017]遗失的答案【dp+FWT】的更多相关文章
- bzoj 5019 [Snoi2017]遗失的答案
题面 https://www.lydsy.com/JudgeOnline/problem.php?id=5019 题解 如果L不是G的倍数 答案为0 下面考虑G|L的情况 将G,L质因数分解 设$L= ...
- 【BZOJ5019】[SNOI2017]遗失的答案(FWT,动态规划)
[BZOJ5019][SNOI2017]遗失的答案(FWT,动态规划) 题面 BZOJ 题解 发现\(10^8\)最多分解为不超过\(8\)个本质不同质数的乘积. 而\(gcd\)和\(lcm\)分别 ...
- BZOJ5019[Snoi2017]遗失的答案——FWT+状压DP
题目描述 小皮球在计算出答案之后,买了一堆皮肤,他心里很开心,但是一不小心,就忘记自己买了哪些皮肤了.==|||万 幸的是,他还记得他把所有皮肤按照1-N来编号,他买来的那些皮肤的编号(他至少买了一款 ...
- 洛谷$P5366\ [SNOI2017]$遗失的答案 数论+$dp$
正解:数论$dp$ 解题报告: 传送门$QwQ$ 考虑先质因数分解.所以$G$就相当于所有系数取$min$,$L$就相当于所有系数取$max$ 这时候考虑,因为数据范围是$1e8$,$1e8$内最多有 ...
- bzoj5019: [Snoi2017]遗失的答案
Description 小皮球在计算出答案之后,买了一堆皮肤,他心里很开心,但是一不小心,就忘记自己买了哪些皮肤了.==|||万 幸的是,他还记得他把所有皮肤按照1-N来编号,他买来的那些皮肤的编号( ...
- [SNOI2017]遗失的答案
题目 首先\(G,L\)肯定会满足\(G|L\),否则直接全部输出\(0\) 之后我们考虑一下能用到的质因数最多只有\(8\)个 同时我们能选择的数\(x\)肯定是\(L\)的约数,还得是\(G\)的 ...
- BZOJ5019 SNOI2017遗失的答案(容斥原理)
显然存在方案的数一定是L的因数,考虑对其因子预处理答案,O(1)回答. 考虑每个质因子,设其在g中有x个,l中有y个,则要求所有选中的数该质因子个数都在[x,y]中,且存在数的质因子个数为x.y.对于 ...
- LOJ2257 SNOI2017 遗失的答案 容斥、高维前缀和
传送门 数字最小公倍数为\(L\)的充分条件是所有数都是\(L\)的约数,而\(10^8\)内最多约数的数的约数也只有\(768\)个.所以我们先暴力找到所有满足是\(L\)的约数.\(G\)的倍数的 ...
- luogu P5366 [SNOI2017]遗失的答案
luogu 首先gcd为\(G\),lcm为\(L\),有可能出现的数(指同时是\(G\)的因数以及是\(L\)的倍数)可以发现只有几百个.如果选出的数要能取到gcd,那么对于每种质因子,都要有一个数 ...
随机推荐
- Android中View自己定义XML属性具体解释以及R.attr与R.styleable的差别
为View加入自己定义XML属性 Android中的各种Widget都提供了非常多XML属性,我们能够利用这些XML属性在layout文件里为Widget的属性赋值. 例如以下所看到的: <Te ...
- insertion-sort-list——链表、插入排序、链表插入
Sort a linked list using insertion sort. PS:需要考虑left为head且只有一个数时,此时left->==NULL,若right<left则应更 ...
- C#语法复习3
第七章 类与继承 1.虽然派生类不能删除基类的的任何成员,但我们可以利用在派生类当中声明与基类成员名称相同的成员来屏蔽基类成员.这叫 覆盖. 一种是隐式屏蔽.一种是显式屏蔽.所谓 显式就是 加上一个n ...
- java栈、堆
一.栈.堆 几个小概念 1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制. 2. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的 ...
- 【翻译自mos文章】多租户中的service管理
来源于: Service Management For Multitenant (文档 ID 2009500.1) APPLIES TO: Oracle Database - Enterprise E ...
- postgres启动过程分析
今天来学习一下pg启动的过程. pg的启动命令./bin/postgres -D path/to/data. 1.主体监控进程 postmaster进程进入无限循环,等待客户端请求并为之提供请求的服务 ...
- mysql 环境变量之 group_concat_max_len
今天使用mysql group_concat()函数,对查询的数据进行字符串连接操作. 不过由于查询的结果较多,连接后的结果很长导致不能完全显示. 查询手册发现如下说明: (先说说group_conc ...
- MYSQL使用inner join 进行 查询/删除/修改示例
代码如下: --查询 SELECT tp.tp_id, tp.tpmc, tp.leveid, tp.tpdz, tp.jgm, tp.scsj, tp.pbzyid, tp.ksbfsj, tp.j ...
- c# 扩展方法奇思妙用基础篇五:Dictionary<TKey, TValue> 扩展
Dictionary<TKey, TValue>类是常用的一个基础类,但用起来有时确不是很方便.本文逐一讨论,并使用扩展方法解决. 向字典中添加键和值 添加键和值使用 Add 方法,但很多 ...
- JavaScript数组的某些操作(一)
在软件开发的过程中JavaScript的编程在所难免.当中对数组的操作尤为常见,这里介绍一下和JavaScript数组相关的某些操作: 1.删除并返回数组的第一个元素--shift方法: <!D ...