【XSY2753】LCM
Description
给你\(n,k\),要你选一些互不相同的正整数,满足这些数的lcm为\(n\),且这些数的和为\(k\)的倍数。
求选择的方案数。对\(232792561\)取模。
\(n\le10^{18},k\le20,n的全部质因子都\le100\)
Solution
\(n\le10^{18}\)时其质因数个数最多只有15个。记\(n\)的质因子个数为\(m\)。
设\(g_{i,j}\)表示有多少个\(n\)的因数\(d\),满足\(d\)中\(i\)状态的质因子的指数与\(n\)相同,且\(d\%k=j\)。
再设\(f_{i,j}\),表示从\(g_{i}\)所涉及的数组成的数集\(A_i\)中有多少个子集,使得子集中的数之和模\(k\)为\(j\)。
这点可以用生成函数解决:
\]
则\(f_{i,j}=G_i(x)[j]\)。
考虑许多个\(f_{i,j}\)怎样组合才对答案有贡献。当下列条件同时满足时:
(1)\(i_1|i_2|...|i_s=2^m-1\)
(2)\(i_1\neq i_2\neq...\neq i_s\)
(3)\(j_1+j_2+...+j_s\equiv0\pmod k\)
则会对\(Ans\)有\(\prod f_{i,j}\)的贡献。
其实我们要求一个数组\(h_{i,j}\)表示任选所有数字,使得\(i\)状态表示的每个质因子\(p\),至少存在一个数满足其\(p\)的指数与\(n\)中相同,且所有数加起来模\(k\)等于\(j\)的方案数。显然答案是\(h_{2^m-1,0}\)。
对每一行\(f_i\)单独做一次DFT,此时得到每行\(f_i\)的点值表达。我们要做的,是选择那些编号或起来恰好等于\(2^m-1\)的行,将它们的点值表达对位相乘,累加到一个新数组\(tmp\),这相当于枚举哪些行参与贡献、枚举这些行的哪一个\(f_{i,j}\)参与贡献。对此\(tmp\)做逆DFT,就可以得到\(h_{i}\)了!
所以这部分如何操作?我们发现每一列的操作模式是相同的且互不影响。那么现在我们只看第一列即\(f_{i,0}\),将这一列数拉出来方便看,设为\(a_i\),其中\(a_i=DFT(f_i)[0]\)。
另起一个命名空间:\(f_i\)表示从\(a\)中选择若干个数使得编号或起来等于\(i\)时所有选择数的乘积,的所有情况之和。
构造莫比乌斯变换\(F_S=\sum_{T\in S}{f_T}=\prod_{i\in S}(1+a_i)\)。最后一个式子只要将括号展开,会得到许多乘积之和,每一个乘积都属于某一个\(f\),因此是成立的。
根据莫比乌斯反演,有\(f_S=\sum_{T\in S}(-1)^{|S|-|T|}F_T\),因此若我们知道\(F\),就可以暴力地求\(f_{2^m-1}\)。那么\(f_{2^m-1}\)其实就是\(tmp\)的第0项,因为它是一种或的组合形式,满足粗体字,解决了一列的操作,那么其他列同理。
\(F\)怎么求呢?这里要用到快速莫比乌斯变换FMT,即求解\(F_S=\prod_{T\in S}g(T)\),其中\(g\)是一个已知函数。
初始时\(F_S=g(S)\)。考虑补全\(F_S\)的内容,即考虑自己\(F_i\)如何去补全别人的\(F_j\)。有一种方式可以无重复地做到这点。\(F_i\)能更新\(F_j\)当且仅当\(j\)是由\(i\)的某一位0改成1得到。从低到高枚举改第\(x\)位,之后从小到大循环\(i\),如果\(i\)的第\(x\)位是0,那么更新\(F_{i+2^x}+=F_i\)。为什么要这样做?因为这样每个\(F_i\)所包含的元素都会只统计一次。假设\(F_i\)中\(g(j)\)被统计了多次,那就说明\(g(j)\)贡献去\(F_i\)的路径出现分叉和合并,即有人先改了高位、有人又先改了低位,两个过程又是同时进行的,这与我们算法设计的“逐位修改”有矛盾。因此可以这么做。
总时间复杂度\(\mathcal O(k^22^m+km2^m)\)。
交题不小心把yww的std交上去了,常数太优秀,我的代码覆盖不掉他。qwq
Code
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int PN=26,MOD=232792561,G=71;
ll n;
int m;
int d[PN],id[PN],idcnt,w[410][2];
int p[PN]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97};
int f[1<<15][20];
inline int bit(int i){return 1<<(i-1);}
int fmi(int x,int y,int mod=MOD){
int res=1;
for(;y;x=1LL*x*x%mod,y>>=1)
if(y&1) res=1LL*res*x%mod;
return res;
}
void init_rt(){
int rt=fmi(G,(MOD-1)/m);
w[0][0]=1;
for(int i=1;i<=400;i++) w[i][0]=1LL*w[i-1][0]*rt%MOD;
for(int i=0;i<=400;i++) w[i][1]=fmi(w[i][0],MOD-2);
}
void dft(int n,int *a,int t){
static int b[30];
for(int i=0;i<n;i++) b[i]=0;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
(b[i]+=1LL*a[j]*w[i*j][t]%MOD)%=MOD;
if(t){
int invn=fmi(n,MOD-2);
for(int i=0;i<n;i++) b[i]=1LL*b[i]*invn%MOD;
}
for(int i=0;i<n;i++) a[i]=b[i];
}
void depart(){
ll x=n;
for(int i=1;i<PN;i++){
d[i]=0;
while(x%p[i]==0) x/=p[i],d[i]++;
if(d[i]) id[i]=++idcnt;
}
}
void add(int x,int y){
static int t[30];
for(int i=0;i<m;i++) t[i]=f[x][i];
for(int i=0;i<m;i++)
(f[x][(i+y)%m]+=t[i])%=MOD;
}
void dfsdiv(int x,int state,int mulmodk){
if(x==PN){
add(state,mulmodk);
return;
}
for(int i=0;i<=d[x];i++){
if(i&&(i==d[x]))
dfsdiv(x+1,state|bit(id[x]),1LL*mulmodk*fmi(p[x],i,m)%m);
else
dfsdiv(x+1,state,1LL*mulmodk*fmi(p[x],i,m)%m);
}
}
void reset(){
memset(f,0,sizeof f);
}
void Main(){
scanf("%lld%d",&n,&m);
init_rt();
idcnt=0;
depart();
int all=1<<idcnt;
for(int i=0;i<all;i++){
f[i][0]=1;
for(int j=1;j<m;j++) f[i][j]=0;
}
dfsdiv(1,0,1);
for(int i=0;i<all;i++) dft(m,f[i],0);
for(int i=1;i<all;i<<=1)
for(int j=0;j<all;j++)
if(!(i&j))
for(int k=0;k<m;k++)
f[j+i][k]=1LL*f[j+i][k]*f[j][k]%MOD;
for(int i=0;i<all-1;i++){
int a=1;
for(int j=0;j<idcnt;j++)
if(!((i>>j)&1)) a=-a;
for(int j=0;j<m;j++)
(f[all-1][j]+=a*f[i][j])%=MOD;
}
dft(m,f[all-1],1);
int ans=f[all-1][0];
printf("%d\n",ans<0?ans+MOD:ans);
}
int main(){
int T;
scanf("%d",&T);
while(T--) Main();
return 0;
}
【XSY2753】LCM的更多相关文章
- 【XSY2753】Lcm 分治 FWT FFT 容斥
题目描述 给你\(n,k\),要你选一些互不相同的正整数,满足这些数的\(lcm\)为\(n\),且这些数的和为\(k\)的倍数. 求选择的方案数.对\(232792561\)取模. \(n\leq ...
- 【倍增】LCM QUERY
给一个序列,每次给一个长度l,问长度为l的区间中lcm最小的. 题解:因为ai<60,所以以某个点为左端点的区间的lcm只有最多60种的情况,而且相同的lcm区间的连续的. 所以就想到一个n*6 ...
- 【BZOJ】【2694】Lcm
数论/莫比乌斯反演/线性筛 题解:http://www.cnblogs.com/zyfzyf/p/4218176.html JZPTAB的加强版?感觉线性筛好像还是不怎么会啊……sad 题目记下来,回 ...
- 【bzoj2694】Lcm 莫比乌斯反演+线性筛
题目描述 求$\sum\limits_{i=1}^n\sum\limits_{j=1}^m|\mu(gcd(i,j))|lcm(i,j)$,即$gcd(i,j)$不存在平方因子的$lcm(i,j)$之 ...
- 【CF1068B】LCM(数学)
题意:给定b,求lcm(a,b)/a有几种不同的取值 b<=1e10 思路:只有a取b的因子时答案两两不同 #include<cstdio> #include<cstring& ...
- 【XSY2470】lcm 数学
题目大意 \(t\)组询问, 每组询问给定\(n\),求\(\sum_{k=1}^n[n,k]\),其中\([a,b]\)表示\(a\)和\(b\)的最小公倍数 . \(t\leq 300000,n\ ...
- 【51NOD-0】1012 最小公倍数LCM
[算法]欧几里德算法 #include<cstdio> int gcd(int a,int b) {?a:gcd(b,a%b);} int main() { int a,b; scanf( ...
- 【原创】开源Math.NET基础数学类库使用(09)相关数论函数使用
本博客所有文章分类的总目录:[总目录]本博客博文总目录-实时更新 开源Math.NET基础数学类库使用总目录:[目录]开源Math.NET基础数学类库使用总目录 前言 ...
- 【wikioi】1012 最大公约数和最小公倍数问题
题目链接 算法:辗转相除(欧几里得) gcd(a, b)是a和b最小公倍数, lcm(a, b)是a和b的最大公倍数 gcd(a, b) == gcd(b, a%b) 时间复杂度: O(lgb) 具体 ...
随机推荐
- sqli-labs学习笔记 DAY8
DAY 8 sqli-lab Page-3 sqli-labs lesson 38 What is Stacked injection? https://blog.csdn.net/Fly_hps/a ...
- MySQL基础练习(三)
经过之前两次的学习,这次用MySQL进行略微复杂的操作练习 各部门工资最高的员工 首先创建表employee和表department.如下 我们需要查询每个部门工资最高的员工 select a.Nam ...
- TCP协议数据包及攻击分析
TCP/IP协议栈中一些报文的含义和作用 URG: Urget pointer is valid (紧急指针字段值有效) SYN: 表示建立连接 FIN: 表示关闭连接 ACK: 表示响应 PSH: ...
- logout命令详解
基础命令学习目录首页 logout指令让用户退出系统,其功能和login指令相互对应.语法 logout
- python将response中的cookies加入到header
url = “http://abad.com”header = { "user-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64 ...
- JSBridge实现示例
前言 参考来源 前人栽树,后台乘凉,本文参考了以下来源 Hybrid APP架构设计思路 marcuswestin/WebViewJavascriptBridge 楔子 本文介绍JSBridge的完整 ...
- 第二阶段Sprint冲刺会议5
进展:能够保存到手机或内存卡上,没有实现自己选路径,指定路径为内存卡并能够播放已录制好的视频.
- 每天学一点easyui②
Form插件 <!DOCTYPE html> <html> <head> <meta charset="utf-8&qu ...
- NABCD(校园包车)
广州商学院包车 N(need) 各个高校包车需求量大,然而校园内包车信息太散乱,售票地点不确定,有些老师.学生特别是新生,甚至不知有校园包车这一回事, 随着信息网络的发展,为了给师生带来校园更多的方便 ...
- grunt入门讲解6:grunt使用步骤和总结
Grunt是啥? 很火的前端自动化小工具,基于任务的命令行构建工具. Grunt能帮我们干啥? 假设有这样一个场景: 编码完成后,你需要做以下工作 HTML去掉注析.换行符 - HtmlMin CSS ...