【Luogu4191】[CTSC2010] 性能优化
题意简述
求循环卷积意义下的 \(A(x)*B(x)^C\)。
模数为 n+1 ,长度为 n。
Sol
板子题。
循环卷积可直接把点值快速幂来解决。
所以问题就是要快速 \(DFT\),由于长度是 n 不一定是NTT模数,我们要解决任意长度的 \(DFT\)
这道题保证了 \(n\) 质因数分解之后的质因子最大不超过 10 。
我们可以模仿朴素 \(FFT\) 对点值分组分别计算然后合并的方法。
每次分成 \(p\) 组然后合并点值即可。根据如下式子:
\(F(x)=\sum a_ix^i\) ,\(F_r(x)=\sum a_{ip+r}x^i\)
\(F(x)=\sum x^rF_r(x^p)\)
\]
写的时候可以类似的用 dfs 预处理出每一个数最后到达的位置
code:
#include<bits/stdc++.h>
#define Set(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=1e6+10;
int mod,g;
template <typename T> inline void init(T&x){
x=0;char ch=getchar();bool t=0;
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
if(t) x=-x;return;
}
typedef long long ll;
template <typename T>inline void Inc(T&x,int y){x+=y;if(x>=mod) x-=mod;return;}
template <typename T>inline void Dec(T&x,int y){x-=y;if(x < 0) x+=mod;return;}
template <typename T>inline int fpow(int x,T k){int ret=1;for(;k;k>>=1,x=(ll)x*x%mod) if(k&1) ret=(ll)ret*x%mod;return ret;}
int Sum(int x,int y){x+=y;if(x>=mod) return x-mod;return x;}
int Dif(int x,int y){x-=y;if(x < 0 ) return x+mod;return x;}
int n,C;int pri[N],cur=0;
inline int Getroot(int p){
int x=p-1;cur=0;
for(int i=2;i*i<=x;++i) while(x%i==0) pri[++cur]=i,x/=i;
if(x>1) pri[++cur]=x;int g;
for(g=2;;++g){bool fl=1;
for(int j=1;j<=cur;++j) if(pri[j]!=pri[j+1]&&fpow(g,p/pri[j])==1) {fl=0;break;}
if(fl) break;
}return g;
}
int rader[N],Po[N],IP[N],A[N],B[N];
int dfs(int s,int p,int now,int blk){
if(now==cur+1)return s+p;
int nxt=blk/pri[now];
return dfs(s+nxt*(p%pri[now]),(p-p%pri[now])/pri[now],now+1,nxt);
}
inline void NTT(int*A,int n,int f){
static int tmp[N];
for(int i=0;i<n;++i) tmp[rader[i]]=A[i];
for(int i=0;i<n;++i) A[i]=tmp[i],tmp[i]=0;
for(int i=1,now=cur;i<n;i*=pri[now],--now){// 模拟 FFT
for(int t=i*pri[now],j=0;j<n;j+=t)
for(int k=0;k<t;k+=i)
for(int l=0;l<i;++l)
for(int o=0;o<pri[now];++o){
if(~f) Inc(tmp[j+k+l],(ll)Po[n/t*(k+l)*o%n]*A[j+i*o+l]%mod);
else Inc(tmp[j+k+l],(ll)IP[n/t*(k+l)*o%n]*A[j+i*o+l]%mod);
}
for(int j=0;j<n;++j) A[j]=tmp[j],tmp[j]=0;
}
if(f==-1) for(int i=0,inv=fpow(n,mod-2);i<n;++i) A[i]=(ll)A[i]*inv%mod;
return;
}
int main()
{
init(n);mod=n+1;init(C);g=Getroot(mod);
Po[0]=IP[0]=1,Po[1]=g,IP[1]=fpow(g,mod-2);
for(int i=0;i<n;++i) init(A[i]);
for(int i=0;i<n;++i) init(B[i]);
for(int i=2;i<n;++i) Po[i]=(ll)Po[i-1]*Po[1]%mod,IP[i]=(ll)IP[i-1]*IP[1]%mod;
for(int i=0;i<n;++i) rader[i]=dfs(0,i,1,n);
NTT(A,n,1);NTT(B,n,1);
for(int i=0;i<n;++i) A[i]=(ll)A[i]*fpow(B[i],C)%mod;
NTT(A,n,-1);
for(int i=0;i<n;++i) printf("%d\n",A[i]);
return 0;
}
本题还有一种常数巨大的完全过不了的算法。(用上合并DFT的科技说不定能过)
还是快速求解任意长度 \(DFT\)。
有一种叫做\(Bluestein’s\; Algorithm\) 的算法。
考虑我们要求解:
\(A(w_n^k)=\sum_{i=0}^{n-1}a_iw_n^{ki}\)
把 \(ki\) 以一种能够构成卷积的方式代换,为了防止出现单位根不存在二次剩余的情况这里选择用组合数替换: \(ki={k+i\choose 2}-{k\choose 2}-{i\choose 2}\)
所以要求的就是:
\(A(w_n^k)=\sum_{i=0}^{n-1}a_iw_n^{{k+i\choose 2}-{k\choose 2}-{i\choose 2}}\)
\(A(w_n^k)=w_n^{-{k\choose 2}} \sum_{i=0}^{n-1}a_iw_n^{{k+i\choose 2}-{i\choose 2}}\)
\(A(w_n^k)=w_n^{-{k\choose 2}} \sum_{i=0}^{n-1}a_iw_n^{-{i\choose 2}} w_n^{{k+i\choose 2}}\)
后面那个东西翻转一下就是一个卷积的形式了,所以我们可以用 \(FFT\) 等多项式卷积算法来计算任意长度\(DFT\) !
但是这道题里显然不能朴素 \(NTT\),因为模数并不是 \(NTT\) 模数。
如果用 \(FFT\) 代替,存在精度误差过不了,那么只能 \(MTT\)。
这样一算下来,我们总共需要 \(DFT\)三次。(\(IDFT\) 和 \(DFT\)没有区别)
每次 \(DFT\) 里我们要用上一个 \(MTT\) ,而\(MTT\)每次要做 \(7\) 次 \(DFT\)。
也就是说我们总共做了 \(3*7=21\) 次 \(DFT\) 。
也就是说 复杂度 \(O(nlog^2n)\)...这个东西比直接倍增算还慢吧...
(哪位大佬有更加优秀的非合并 \(DFT\) 的做法来教教我啊)
80'code:
#include<bits/stdc++.h>
#define Set(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=5e5+10;
const int MAXN=2097152;
int mod,g;
template <typename T> inline void init(T&x){
x=0;char ch=getchar();bool t=0;
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
if(t) x=-x;return;
}
typedef long long ll;
template <typename T>inline void Inc(T&x,int y){x+=y;if(x>=mod) x-=mod;return;}
template <typename T>inline void Dec(T&x,int y){x-=y;if(x < 0) x+=mod;return;}
template <typename T>inline int fpow(int x,T k){int ret=1;for(;k;k>>=1,x=(ll)x*x%mod) if(k&1) ret=(ll)ret*x%mod;return ret;}
int Sum(int x,int y){x+=y;if(x>=mod) return x-mod;return x;}
int Dif(int x,int y){x-=y;if(x < 0 ) return x+mod;return x;}
int n,C;int pri[N],cur=0;
inline int Getroot(int p){
int x=p-1;cur=0;
for(int i=2;i*i<=x;++i) while(x%i==0) pri[++cur]=i,x/=i;
if(x>1) pri[++cur]=x;int g;
for(g=2;;++g){bool fl=1;
for(int j=1;j<=cur;++j) if(pri[j]!=pri[j+1]&&fpow(g,p/pri[j])==1) {fl=0;break;}
if(fl) break;
}return g;
}
int rader[MAXN],Po[N],IP[N],A[N],B[N];
inline int Init(int n){
int len=1,up=-1;for(;len<=n;len<<=1,++up);
for(int i=0;i<len;++i) rader[i]=(rader[i>>1]>>1)|((i&1)<<up);
return len;
}
typedef double db;
namespace MTT{
const db PI=acos(-1);
struct Complex{
db x,y;Complex(db _x=0.0,db _y=0.0){x=_x,y=_y;}
inline Complex operator +(const Complex B){return Complex(x+B.x,y+B.y);}
inline Complex operator -(const Complex B){return Complex(x-B.x,y-B.y);}
inline Complex operator *(const Complex B){return Complex(x*B.x-y*B.y,x*B.y+y*B.x);}
}w[MAXN];
inline void Calc(int n){for(int i=1;i<n;i<<=1) for(int j=0;j<i;++j) w[n/i*j]=Complex(cos(PI/i*j),sin(PI/i*j));return;}
inline void FFT(Complex*A,int n,int f){
for(int i=0;i<n;++i) if(rader[i]>i) swap(A[rader[i]],A[i]);
for(int i=1;i<n;i<<=1)
for(int j=0,p=i<<1;j<n;j+=p)
for(int k=0;k<i;++k){
Complex X=A[j|k],Y=A[j|k|i]* ((~f)? w[n/i*k]:Complex(w[n/i*k].x,-w[n/i*k].y));
A[j|k]=X+Y,A[j|k|i]=X-Y;
}
if(!~f) for(int i=0;i<n;++i) A[i].x/=(db)n;return;
}
inline void Mul(int*A,int*B,int*C,int len){
static Complex A1[MAXN],A2[MAXN],B1[MAXN],B2[MAXN];
int MO=sqrt(mod);
for(int i=0;i<len;++i) A1[i]=Complex(A[i]/MO,0.0),B1[i]=Complex(A[i]%MO,0.0),A2[i]=Complex(B[i]/MO,0.0),B2[i]=Complex(B[i]%MO,0.0);
FFT(A1,len,1),FFT(A2,len,1),FFT(B1,len,1),FFT(B2,len,1);
for(int i=0;i<len;++i) {Complex X;
X=A1[i]*A2[i],A2[i]=A2[i]*B1[i];
B1[i]=B1[i]*B2[i];B2[i]=B2[i]*A1[i];
A1[i]=X,A2[i]=A2[i]+B2[i];
}int MOD=MO*MO%mod;
FFT(A1,len,-1),FFT(B1,len,-1),FFT(A2,len,-1);
for(int i=0;i<len;++i) {
int X=(ll)(A1[i].x+0.5)%mod,Y=(ll)(B1[i].x+0.5)%mod,Z=(ll)(A2[i].x+0.5)%mod;
int ans=(ll)MOD*X%mod;Inc(ans,(ll)MO*Z%mod);Inc(ans,Y);
C[i]=ans;
}return;
}
}using MTT::Calc;
inline int Co(int x){return (ll)x*(x-1)/2%n;}
inline void DFT(int*A,int n,int len,int f){
int m=2*n-1;static int F[MAXN],G[MAXN];
if(~f) {
for(int i=0;i<n;++i) F[i]=(ll)A[i]*IP[Co(i)]%mod;for(int i=n;i<len;++i) F[i]=0;
for(int i=0;i<m;++i) G[i]=Po[Co(i)];for(int i=m;i<len;++i) G[i]=0;
}
else {
for(int i=0;i<n;++i) F[i]=(ll)A[i]*Po[Co(i)]%mod;for(int i=n;i<len;++i) F[i]=0;
for(int i=0;i<m;++i) G[i]=IP[Co(i)];for(int i=m;i<len;++i) G[i]=0;
}reverse(F,F+n);MTT::Mul(F,G,F,len);
for(int k=0,i=n-1;i<m;++i,++k) {
if(~f) A[k]=(ll)F[i]*IP[Co(k)]%mod;
else A[k]=(ll)F[i]*Po[Co(k)]%mod;
}
if(!~f) for(int i=0,inv=fpow(n,mod-2);i<n;++i) A[i]=(ll)A[i]*inv%mod;
return;
}
int main()
{
init(n);mod=n+1;init(C);g=Getroot(mod);
Po[0]=IP[0]=1,Po[1]=g,IP[1]=fpow(g,mod-2);
for(int i=0;i<n;++i) init(A[i]),A[i]%=mod;
for(int i=0;i<n;++i) init(B[i]),B[i]%=mod;
for(int i=2;i<n;++i) Po[i]=(ll)Po[i-1]*Po[1]%mod,IP[i]=(ll)IP[i-1]*IP[1]%mod;
int len=Init(3*n-3);Calc(len);
DFT(A,n,len,1);DFT(B,n,len,1);
for(int i=0;i<n;++i) A[i]=(ll)A[i]*fpow(B[i],C)%mod;
DFT(A,n,len,-1);
for(int i=0;i<n;++i) printf("%d\n",A[i]);
return 0;
}
【Luogu4191】[CTSC2010] 性能优化的更多相关文章
- Luogu4191 [CTSC2010]性能优化【多项式,循环卷积】
题目描述:设$A,B$为$n-1$次多项式,求$A*B^C$在系数模$n+1$,长度为$n$的循环卷积. 数据范围:$n\leq 5*10^5,C\leq 10^9$,且$n$的质因子不超过7,$n+ ...
- [CTSC2010]性能优化
[CTSC2010]性能优化 循环卷积快速幂 两个注意点:n+1不是2^k*P+1形式,任意模数又太慢?n=2^k1*3^k2*5^k3*7^k4 多路分治!深刻理解FFT运算本质:分治,推式子得到从 ...
- Luogu4191:[CTSC2010]性能优化
传送门 题目翻译:给定两个 \(n\) 次多项式 \(A,B\) 和一个整数 \(C\),求 \(A\times B^C\) 在模 \(x^n\) 意义下的卷积 显然就是个循环卷积,所以只要代入 \( ...
- 01.SQLServer性能优化之----强大的文件组----分盘存储
汇总篇:http://www.cnblogs.com/dunitian/p/4822808.html#tsql 文章内容皆自己的理解,如有不足之处欢迎指正~谢谢 前天有学弟问逆天:“逆天,有没有一种方 ...
- 03.SQLServer性能优化之---存储优化系列
汇总篇:http://www.cnblogs.com/dunitian/p/4822808.html#tsql 概 述:http://www.cnblogs.com/dunitian/p/60413 ...
- Web性能优化:What? Why? How?
为什么要提升web性能? Web性能黄金准则:只有10%~20%的最终用户响应时间花在了下载html文档上,其余的80%~90%时间花在了下载页面组件上. web性能对于用户体验有及其重要的影响,根据 ...
- Web性能优化:图片优化
程序员都是懒孩子,想直接看自动优化的点:传送门 我自己的Blog:http://cabbit.me/web-image-optimization/ HTTP Archieve有个统计,图片内容已经占到 ...
- C#中那些[举手之劳]的性能优化
隔了很久没写东西了,主要是最近比较忙,更主要的是最近比较懒...... 其实这篇很早就想写了 工作和生活中经常可以看到一些程序猿,写代码的时候只关注代码的逻辑性,而不考虑运行效率 其实这对大多数程序猿 ...
- JavaScript性能优化
如今主流浏览器都在比拼JavaScript引擎的执行速度,但最终都会达到一个理论极限,即无限接近编译后程序执行速度. 这种情况下决定程序速度的另一个重要因素就是代码本身. 在这里我们会分门别类的介绍J ...
随机推荐
- 如何将EDM数据分类工作做的更加真善美
众所周知,数据是互联网时代营销的决定性因素,数据的好坏关乎到营销能力的强弱,而细化到EDM行业中,数据细分变得极为重要,根据数据形态的不同,将会涉及到多种不同的细分方法,有效的利用这些方法,将会大大的 ...
- 算法初级(scala)
来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/two-sum 1.给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为 ...
- Java ——多线程编程
本节重点思维导图 多线程编程
- redis在ubuntu下的安装
安装: 1.apt-get install redis 2.接下来输入redis-cli,登陆redis,然后就可以操作redis了 卸载 在ubuntu下卸载redis 1. 卸载软件 apt-ge ...
- Linux系统常用命令之top
top - 06:58:37 up 7 days, 23:36, 2 users, load average: 0.00, 0.01, 0.05Tasks: 716 total, 1 running, ...
- [JS] 鼠标点击文本框清空默认值,离开文本框恢复默认值
在使用文本框的时候,若设定了初始值,选择文本框进行输入的时候要将本来的内容进行删除,会显得非常麻烦 可以在文本框属性定义触发onfocus和onblur两个事件时对应的js功能 下面以asp.net代 ...
- 【烦人的字符集】linux字符集问题,中文乱码
[1]快速修改命令 [2]locale 查看现在服务器的字符 [root@Master ~]# localeLANG=en_US.UTF-8LC_CTYPE="zh_CN.UTF-8&quo ...
- 剑指Offer编程题(Java实现)——从尾到头打印链表
题目描述 输入一个链表,按链表值从尾到头的顺序返回一个ArrayList. 解题思路 思路一:使用头插法 使用头插法可以得到一个逆序的链表.遍历链表,每次将所遍历节点插入到链表的头部. 头结点和第一个 ...
- 粉丝福利:收藏已久的Java架构资料免费送(仅限3天)
有段时间没跟各位粉丝分享编程资源福利了,看了下自己的百度网盘,就剩下这个我认为是比较好的Java架构师学习资料了,相信这套资料可以对你进阶高级工程师有帮助. Java架构师技术进阶路线图 架构技术进阶 ...
- uboot第二阶段分析1
一. uboot第二阶段初识 1.1. uboot第二阶段应该做什么 a. 概括来讲uboot第一阶段主要就是初始化了SoC内部的一些部件(譬如看门狗.时钟),然后初始化DDR并且完成重定位. b. ...