【2018北京集训6】Lcm DFT&FWT
首先我们来看下此题的模数232792561。
232792561=lcm(1,2,3.......20)+1。这个性质将在求值时用到。
我们将n分解质因数,令m为n的素因子个数,设n=Πm−1j=0pbjj ,其中pj是素数且p0至pm−1从小到大排列。考虑到n≤1018,则m≤15。
我们用 f[i][j] 表示当前n的因数x所表示的状态为i,且模k为j时的方案数。
下面讲下如何用一个已知的因数x求出i。
设x=Πm−1j=0pdjj ,则i=∑m−1j=02j×[dj==bj] 。(此处举个例子,令n=12,则当x=6时,i=2,当x=12时,i=3,如果还是不清楚的话可以去看我的代码)
据此定义,则答案显然为f[2m−1][0]。
初始化:对于∀n%x==0 有 f[i][x%k]=1
下面考虑如何转移。
显然,朴素的转移方法是会超时的(说白了就是只有10分),那么考虑如何加速转移。
首先,我们现在f[i][0...2m−1][]中完成同层的转移(详情见代码)
假设我们去取出数量相同的c和b,使得Πf[bl][ci] 可以对f[2m−1][0]产生贡献。
考虑可对f[2m−1][0]产生贡献的条件,显然有三:
b1 or b2 or .....bp=2m−1
b1≠b2≠.....≠bp
c1 + c2 + ..... cp ≡0(mod k)
对于这两条限制,直接对每一行(既f[i])先做一次DFT以满足性质3,然后对每一列(即f[][j])做一次FWT以满足性质1和性质2(没错通过这种嵌套即可同时满足两个性质),然后将最后一列做一次IDFT,即可求出f[2m−1][0]
此题看题5分钟,懵逼4小时,写题1小时.....
1 #include<bits/stdc++.h> 2 #define M 20000000 3 #define MOD 232792561 4 #define L long long 5 using namespace std; 6 L pow_mod(L x,int k){ 7 L ans=1; 8 while(k){ 9 if(k&1) ans=ans*x%MOD; 10 x=x*x%MOD; k>>=1; 11 } 12 return ans; 13 } 14 L f[1<<15][20]={0}; 15 L n,m,nn,e[20]={0},d[20]={0},p[20]={0},a[M]={0}; int k; 16 17 void DFT(L a[],L w[],int n,int on){ 18 L b[20]; memset(b,0,sizeof(b)); 19 for(int i=0;i<n;i++) 20 for(int j=0;j<n;j++) 21 b[i]=(b[i]+a[j]*w[i*j])%MOD; 22 memcpy(a,b,160); 23 if(on==-1){ 24 L inv=pow_mod(n,MOD-2); 25 for(int i=0;i<n;i++) a[i]=a[i]*inv%MOD; 26 } 27 } 28 29 void fenjie(L n){//分解质因数 30 for(int i=2;i<=100;i++) 31 if(n%i==0){ 32 m++; p[m]=i; e[m]=1; 33 while(n%i==0) n/=i,d[m]++,e[m]*=i; 34 } 35 } 36 void coushu(int x,L ji){//凑出所有约数 37 if(x>m) {a[++nn]=ji; return;} 38 coushu(x+1,ji); 39 for(int i=1;i<=d[x];i++){ 40 ji*=p[x]; 41 coushu(x+1,ji); 42 } 43 } 44 45 void add(int x,int nk){ 46 L b[20]; 47 memcpy(b,f[x],160); 48 for(int i=0;i<k;i++) 49 f[x][i]=(f[x][i]+b[(i-nk+k)%k])%MOD; 50 f[x][nk]=(f[x][nk]+1)%MOD; 51 } 52 L w1[500]={0},w2[500]={0}; 53 void sub(){ 54 memset(e,0,sizeof(e)); memset(d,0,sizeof(d)); 55 memset(p,0,sizeof(p)); memset(a,0,sizeof(a)); 56 memset(f,0,sizeof(f)); m=nn=0; 57 cin>>n>>k; 58 L w=pow_mod(71,(MOD-1)/k); w1[0]=w2[0]=1; 59 for(int i=1;i<500;i++){ 60 w1[i]=w1[i-1]*w%MOD; 61 w2[i]=pow_mod(w1[i],MOD-2); 62 } 63 m=0; fenjie(n); 64 coushu(0,1); 65 for(int i=1;i<=nn;i++){ 66 int id=0; 67 for(int j=1;j<=m;j++) 68 if(a[i]%e[j]==0) id=id|(1<<(j-1)); 69 add(id,a[i]%k); 70 } 71 int mm=1<<m; 72 for(int i=0;i<mm;i++) DFT(f[i],w1,k,1); 73 for(int i=0;i<mm;i++) 74 for(int j=0;j<k;j++) f[i][j]++; 75 76 for(int i=1;i<mm;i<<=1) 77 for(int j=0;j<mm;j++) 78 if(i&j){ 79 for(int l=0;l<k;l++) 80 f[j][l]=f[j][l]*f[i^j][l]%MOD; 81 } 82 for(int i=1;i<mm;i<<=1) 83 for(int j=0;j<mm;j++) 84 if(i&j){ 85 for(int l=0;l<k;l++) 86 f[j][l]=(f[j][l]-f[i^j][l]+MOD)%MOD; 87 } 88 DFT(f[mm-1],w2,k,-1); 89 printf("%lld\n",f[mm-1][0]); 90 } 91 92 int main(){ 93 int cas; scanf("%d",&cas); 94 while(cas--) sub(); 95 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!