题目链接

题意简述

求循环卷积意义下的 \(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)\)

\[F(w_n^{an+b})=\sum_{r=0} w_{np}^{(an+b)r}F_r(w_n^b)
\]

写的时候可以类似的用 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] 性能优化的更多相关文章

  1. Luogu4191 [CTSC2010]性能优化【多项式,循环卷积】

    题目描述:设$A,B$为$n-1$次多项式,求$A*B^C$在系数模$n+1$,长度为$n$的循环卷积. 数据范围:$n\leq 5*10^5,C\leq 10^9$,且$n$的质因子不超过7,$n+ ...

  2. [CTSC2010]性能优化

    [CTSC2010]性能优化 循环卷积快速幂 两个注意点:n+1不是2^k*P+1形式,任意模数又太慢?n=2^k1*3^k2*5^k3*7^k4 多路分治!深刻理解FFT运算本质:分治,推式子得到从 ...

  3. Luogu4191:[CTSC2010]性能优化

    传送门 题目翻译:给定两个 \(n\) 次多项式 \(A,B\) 和一个整数 \(C\),求 \(A\times B^C\) 在模 \(x^n\) 意义下的卷积 显然就是个循环卷积,所以只要代入 \( ...

  4. 01.SQLServer性能优化之----强大的文件组----分盘存储

    汇总篇:http://www.cnblogs.com/dunitian/p/4822808.html#tsql 文章内容皆自己的理解,如有不足之处欢迎指正~谢谢 前天有学弟问逆天:“逆天,有没有一种方 ...

  5. 03.SQLServer性能优化之---存储优化系列

    汇总篇:http://www.cnblogs.com/dunitian/p/4822808.html#tsql 概  述:http://www.cnblogs.com/dunitian/p/60413 ...

  6. Web性能优化:What? Why? How?

    为什么要提升web性能? Web性能黄金准则:只有10%~20%的最终用户响应时间花在了下载html文档上,其余的80%~90%时间花在了下载页面组件上. web性能对于用户体验有及其重要的影响,根据 ...

  7. Web性能优化:图片优化

    程序员都是懒孩子,想直接看自动优化的点:传送门 我自己的Blog:http://cabbit.me/web-image-optimization/ HTTP Archieve有个统计,图片内容已经占到 ...

  8. C#中那些[举手之劳]的性能优化

    隔了很久没写东西了,主要是最近比较忙,更主要的是最近比较懒...... 其实这篇很早就想写了 工作和生活中经常可以看到一些程序猿,写代码的时候只关注代码的逻辑性,而不考虑运行效率 其实这对大多数程序猿 ...

  9. JavaScript性能优化

    如今主流浏览器都在比拼JavaScript引擎的执行速度,但最终都会达到一个理论极限,即无限接近编译后程序执行速度. 这种情况下决定程序速度的另一个重要因素就是代码本身. 在这里我们会分门别类的介绍J ...

随机推荐

  1. java hashset输出

    for (Map.Entry<String, String> me : id_label_map.entrySet()) { System.out.println(me.getKey() ...

  2. JS中数组的拷贝方法

    之前在写一个vue的计算属性时,大概是这样: computed: { updateList () { let newList = this.List /*do something*/ return n ...

  3. linux打包

    1.打成tar包 sudo tar -zcf boot.tar /boot/ 2.打成zip包 sudo zip -r boot.zip ./*

  4. 【SQL系列】从SQL语言的分类谈COMMIT和ROLLBACK的用法

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[SQL系列]从SQL语言的分类谈COMMIT和 ...

  5. if you wanna the rainbow, you have to deal with the rain.

    bulk. n. 大量 reluctant. adj. 不情愿的 terrorist. n. 恐怖分子 recognition. n. 认出 tout.v. 兜售 conceal.v. 隐藏 dras ...

  6. Go语言入门篇-环境准备

    一.GO语言特点 静态类型:首先要明确变量类型,如上所示. 编译型:指GO语言要被编译成机器能识别机器代码. GO语言开源. 编程范式:支持“函数式”和“面向对象” GO语言原生的支持并发编程:即GO ...

  7. 第二周JAVA总结

    学海无涯,在学习这件事情上得用点心了

  8. java 异常体系详细介绍

    一.异常概述与异常体系结构 异常:在Java语言中,将程序执行中发生的不正常情况称为"异常".(开发过程中的语法错误和逻辑错误不是异常). Java把异常当作对象来处理,并定义一个 ...

  9. C++基础-类和对象

    本文为 C++ 学习笔记,参考<Sams Teach Yourself C++ in One Hour a Day>第 8 版.<C++ Primer>第 5 版.<代码 ...

  10. [LeetCode] 154. 寻找旋转排序数组中的最小值 II

    题目链接 : https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/ 题目描述: 假设按照升序排序的数组在预 ...