题目描述

  给你\(n,k\),要你选一些互不相同的正整数,满足这些数的\(lcm\)为\(n\),且这些数的和为\(k\)的倍数。

  求选择的方案数。对\(232792561\)取模。

  \(n\leq {10}^{18},k\leq 20\),\(n\)的全部质因子都\(\leq 100\)

题解

解法一

  一个\(\leq {10}^{18}\)的数最多有\(15\)不同的质因子。

  记\(w=15,m=2^w=32768\)

  先看看这个模数有什么特点。

  \(p=232792561=lcm(1,2,\ldots,20)+1\)

  这告诉我们可以对长度在\(1\ldots 20\)的区间DFT。

  所以可以在所有用到模\(k\)的余数的地方DFT,然后对于每个余数做要做的事情。

  对于一个数,如果这个数的某个质因子的最高次幂\(\neq n\)的这个质因子的最高次幂,这个质因子是没有用的。

  这样可以把一个数\(x\)表示成一个数对\(g(x)=(i,j)\),其中\(i\)是一个状态,表示\(x\)有哪些质因子的最高次幂和\(n\)的最高次幂相同。\(j\)表示这个数模\(k\)的余数。

  先暴力枚举所有\(n\)的因子(\(\approx {10}^5\)个),记\(a_{i,j}\)表示有多少个数\(x\)对应的数对\(g(x)=(i,j)\)。

  现在对于每一个\(i\),计算只取这些数,和模\(k\)为\(j=0\ldots k-1\)的方案数\(f_{i,j}\)。

  记\(F_i(x)=\sum_{i=0}^{k-1}f_{i,j}x^j\),那么有\(F_i(x)=\prod_{i=0}^{k-1}{(1+x^i)}^{a_{i,j}}\mod x^k\)。(当然你也可以用一些其他的方法计算,比如说每加一个数进去就维护一下)

  算出\(F_i(x)\)之后做一遍DFT,这样各个\(j\)之间就互不影响了。在做完接下来的步骤后IDFT回来,然后取\(j=0\)的值就是答案了。

  剩下的步骤我们认为\(k=1\),即不考虑模\(k\)的余数。

  现在我们要取一些\(i\)出来,满足\(i_1~or~i_2~or,\cdots,or~i_m\),把答案加上\(f_{i_1}f_{i_2}\cdots f_{i_m}\)。

  令\(g_{i,j}=\begin{cases}f_i&j=i\\0&j\neq i\end{cases}\),那么我们要求的答案就是一个类似\(g_1\oplus g_2\oplus\cdots\oplus g_m\)的东西(实际上在DFT之前\(g_{i,0}\)要\(+1\)表示不选,DFT之后每一位都要\(+1\))。这里\(\oplus\)是集合或卷积。

  直接做的复杂度是\(O(w4^w)\),太慢了。

  注意到\(g_i\)只有一项非零,所以可能有更快的做法。

  考虑分治,观察怎么把两个状态合并。

  合并的时候记左边的结果为

  \(A_1\),右边的结果为\(A_2\),那么合并之后的就是\(A_1+A_2+A_1A_2\)。

  合并的两个数组是长这样的:

  整个数组是一个部分重复很多次。

![](https://images2018.cnblogs.com/blog/1097689/201803/1097689-20180319083442163-80799273.png)

  我们可以只储存&计算循环节部分,要用更长的部分的时候再扩展。

  另一种理解是:每个\(g_{i,j}\)对答案的\(s_l(j\subseteq l)\)都有贡献,这个贡献是乘上去的(因为是在FWT后对应位乘起来)。

  因为前面已经做过一次求幂了(\(F_i(x)\)),所以你也可以这几步先不做(求幂和乘法),在最后做一次求幂。这个就是下面的容斥做法。

  总时间复杂度是\(O(k^22^w+kw2^w)\)

解法二

  一个容斥的做法。

  记\(g_{i,j}\)为有多少个数满足:对于\(i\)中每个\(1\)的二进制位,这些位对应的质因子的次数要取到上限,剩下位的可以任意取,且这个数模\(k\)为\(j\)。

  \(G_i(x)=\sum_{j=0}^{k-1}{(1+x^j)}^{g_{i,j}}\)

  然后容斥一下,容斥过程就是IFWT。

  那么把这个东西做一遍IFWT就是答案了。

  时间复杂度和上面的差不多。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int p=232792561;
const int root=71;
ll fp(ll a,ll b)
{
ll s=1;
for(;b;b>>=1,a=a*a%p)
if(b&1)
s=s*a%p;
return s;
}
int w[1010];
int w2[1010];
ll n;
int m,k,cnt;
ll a[200010];
int d[100];
int c[100];
ll e[100];
int all;
void dft(int *a,int n)
{
static int b[100];
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]=(b[i]+(ll)a[j]*w[i*j])%p;
for(int i=0;i<n;i++)
a[i]=b[i];
}
void idft(int *a,int n)
{
static int b[100];
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]=(b[i]+(ll)a[j]*w2[i*j])%p;
int inv=fp(n,p-2);
for(int i=0;i<n;i++)
a[i]=(ll)b[i]*inv%p;
}
void getfactor(int x,ll s)
{
if(x>m)
{
a[++cnt]=s;
return;
}
for(int i=0;i<=d[x];i++,s*=c[x])
getfactor(x+1,s);
}
int f[50000][20];
int g[50000][20];
void gao(int x,int y,int s)
{
if(x==0)
{
// for(int i=0;i<k;i++)
// f[y][i]=b[s][i];
// dft(f[y],k);
// idft(f[y],k);
return;
}
gao(x-1,y,s);
gao(x-1,y+(1<<(x-1)),s|(1<<(x-1)));
for(int i=y+(1<<(x-1));i<y+(1<<x);i++)
for(int j=0;j<k;j++)
{
g[i][j]=f[i][j];
f[i][j]=f[i-(1<<(x-1))][j];
// f[i][j]=1;
}
for(int i=y;i<y+(1<<(x-1));i++)
for(int j=0;j<k;j++)
// g[i][j]=1;
g[i][j]=0;
for(int i=y;i<y+(1<<x);i++)
for(int j=0;j<k;j++)
f[i][j]=(f[i][j]+g[i][j]+(ll)f[i][j]*g[i][j])%p;
}
void add(int x,int y)
{
static int c[20];
for(int i=0;i<k;i++)
c[i]=f[x][i];
for(int i=0;i<k;i++)
f[x][(i+y)%k]=(f[x][(i+y)%k]+c[i])%p;
f[x][y]=(f[x][y]+1)%p;
}
void solve()
{
scanf("%lld%d",&n,&k);
w[0]=1;
ll rt=fp(root,(p-1)/k);
for(int i=1;i<=1000;i++)
w[i]=(ll)w[i-1]*rt%p;
for(int i=0;i<=1000;i++)
w2[i]=fp(w[i],p-2);
m=0;
for(int i=2;i<=100;i++)
if(n%i==0)
{
m++;
c[m]=i;
d[m]=0;
e[m]=1;
while(n%i==0)
{
n/=i;
d[m]++;
e[m]*=i;
}
}
cnt=0;
getfactor(1,1);
memset(f,0,sizeof f);
for(int i=1;i<=cnt;i++)
{
int s=0;
for(int j=1;j<=m;j++)
if(a[i]%e[j]==0)
s|=1<<(j-1);
add(s,a[i]%k);
}
for(int i=0;i<1<<m;i++)
{
f[i][0]++;
dft(f[i],k);
}
// gao(m,0,0);
for(int i=1;i<1<<m;i<<=1)
for(int j=0;j<1<<m;j++)
if(j&i)
for(int l=0;l<k;l++)
f[j][l]=(ll)f[j][l]*f[j-i][l]%p;
// for(int j=1;j<1<<m;j<<=1)
// for(int l=0;l<1<<m;l++)
// if(j&l)
// for(int i=0;i<k;i++)
// f[l][i]=(f[l][i]-f[l-j][i])%p;
int all=(1<<m)-1;
for(int i=0;i<all;i++)
{
int v=1;
for(int j=0;j<m;j++)
if(!((i>>j)&1))
v=-v;
for(int j=0;j<k;j++)
f[all][j]=(f[all][j]+v*f[i][j])%p;
}
idft(f[all],k);
ll ans=f[all][0];
ans=(ans+p)%p;
printf("%lld\n",ans);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
int t;
scanf("%d",&t);
while(t--)
solve();
return 0;
}

【XSY2753】Lcm 分治 FWT FFT 容斥的更多相关文章

  1. HDU 4609 3-idiots FFT+容斥

    一点吐槽:我看网上很多分析,都是在分析这个题的时候,讲了半天的FFT,其实我感觉更多的把FFT当工具用就好了 分析:这个题如果数据小,统计两个相加为 x 的个数这一步骤(这个步骤其实就是求卷积啊),完 ...

  2. spoj TSUM - Triple Sums fft+容斥

    题目链接 首先忽略 i < j < k这个条件.那么我们构造多项式$$A(x) = \sum_{1现在我们考虑容斥:1. $ (\sum_{}x)^3 = \sum_{}x^3 + 3\s ...

  3. 【BZOJ 3771】 3771: Triple (FFT+容斥)

    3771: Triple Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 547  Solved: 307 Description 我们讲一个悲伤的故事. ...

  4. BZOJ 3771: Triple(FFT+容斥)

    题面 Description 我们讲一个悲伤的故事. 从前有一个贫穷的樵夫在河边砍柴. 这时候河里出现了一个水神,夺过了他的斧头,说: "这把斧头,是不是你的?" 樵夫一看:&qu ...

  5. 模板—点分治A(容斥)(洛谷P2634 [国家集训队]聪聪可可)

    洛谷P2634 [国家集训队]聪聪可可 静态点分治 一开始还以为要把分治树建出来……• 树的结构不发生改变,点权边权都不变,那么我们利用刚刚的思路,有两种具体的分治方法.• A:朴素做法,直接找重心, ...

  6. SPOJ TSUM Triple Sums(FFT + 容斥)

    题目 Source http://www.spoj.com/problems/TSUM/ Description You're given a sequence s of N distinct int ...

  7. SPOJ - TSUM 母函数+FFT+容斥

    题意:n个数,任取三个加起来,问每个可能的结果的方案数. 题解:构造母函数ABC,比如现在有 1 2 3 三个数.则 其中B表示同一个数加两次,C表示用三次.然后考虑去重. A^3表示可重复地拿三个. ...

  8. BZOJ.3771.Triple(母函数 FFT 容斥)

    题目链接 \(Description\) 有\(n\)个物品(斧头),每个物品价值不同且只有一件,问取出一件.两件.三件物品,所有可能得到的价值和及其方案数.\((a,b),(b,a)\)算作一种方案 ...

  9. 【LOJ#575】【LNR#2】不等关系(容斥,动态规划,分治FFT)

    [LOJ#575][LNR#2]不等关系(容斥,动态规划,分治FFT) 题面 LOJ 题解 一个暴力\(dp\),设\(f[i][j]\)表示考虑完了前\(i\)个位置,其中最后一个数在前面所有数中排 ...

随机推荐

  1. MSSQL清理日志\删除数据\收缩数据库

    首先解释一下数据库的版本是SQL Server 2012.清除的数据库800多G,磁盘空间就剩10多G,数据量最多的表有2亿.目的就是清楚去年的数据(2017年之前),遇到了一些问题,总结起来就是三方 ...

  2. Python api接口和SQL数据库关联

    数据库表创建 服务器环境配置.连接 .操作.数据库 API接口  原则:

  3. 使用git将本地项目推送到码云私有仓库

    https://blog.csdn.net/qq_33876553/article/details/80111946 2018年04月27日 19:53:33 桥路丶 阅读数:2958 前言 之前博主 ...

  4. Ajax中文乱码的解决

    网上有很多解决Ajax中文乱码的例子,昨晚弄了很久,最终确定一种“确实”有效地方法.首先我有必要说明一下我遇到的情况:有一个注册页面,注册用户填完信息并提交后,页面获得信息并通过java servle ...

  5. 利用php查看某个服务的进程数

    查看进程就是使用ps命令而已,只不顾ps的参数太多了. 使用php查询的话,必须要开启几个函数(可以执行外部程序的函数),参考官网:http://php.net/manual/zh/book.exec ...

  6. spring datasource jdbc 密码 加解密

    spring datasource 密码加密后运行时解密的解决办法 - 一号门-程序员的工作,程序员的生活(java,python,delphi实战)http://www.yihaomen.com/a ...

  7. windows中dir命令

    最近想用dos命令打印指定目录下的所有文件夹的完整路径.最终发现可用dir命令来实现.在此学习下dir的各项命令. 32位win7系统上,打印帮助文档. D:\test>dir /? 显示目录中 ...

  8. MT4下载历史数据

    这个网站只能下载2001年-当前时间前一个月的数据,还是挺全的.但是下载下来之后好像是一分钟图的,妈蛋其实我想要1小时图的EURUSD历史数据. 网站地址:http://www.fxfupan.com ...

  9. Python--文件、文件夹、压缩包、处理模块shutil

    高级的 文件.文件夹.压缩包 处理模块 shutil.copyfileobj(fsrc, fdst[, length])将文件内容拷贝到另一个文件中 1 import shutil 2 3 shuti ...

  10. Java8新特性之Collectors

    参考:Java8新特性之Collectors 在第二天,你已经学习了Stream API能够让你以声明式的方式帮助你处理集合.我们看到collect是一个将管道流的结果集到一个list中的结束操作.c ...