题目来源:http://www.fjutacm.com/Problem.jsp?pid=3283

题意:给两串长度为n的数组a和b,视为环,a和b可以在任意位置开始互相匹配得到这个函数的值,求这个函数的值最大是多少;

很明显是FFT,但是数据范围是n是1e5,a[i]和b[i]是1e6;精度会丢很多,也就是要NTT解决,那么要选一个不会影响答案的P,因为最大值为1e5*1e6*1e6;那么我们选一个1e17以上的就差不多了,然后就是求循环卷积的步骤,对此,我建议你们算一下这个,[a1、a2、a3、a1、a2、a3]*[b1、b2、b3],列出全部结果(乘法一样的操作,注意每一位乘法的偏移位置),你会发现得到的新集合去掉头上n-1个以及尾部n-1个就可以得到全部的线性卷积组合,那么我们就可以求那个两个数组的卷积得到的数组里直接找最大:

 #include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll PMOD=(27ll<<)+, PR=;
const int N=1e6+;
static ll qp[];
ll res[N];
inline ll Mul(ll a,ll b){
if(a>=PMOD)a%=PMOD;
if(b>=PMOD)b%=PMOD;
return (a*b-(ll)(a/(long double)PMOD*b+1e-)*PMOD+PMOD)%PMOD;
}
struct NTT__container{
NTT__container( ){
int t,i;
for( i=; i<; i++){///注意循环上界与2n次幂上界相同
t=<<i;
qp[i]=quick_pow(PR,(PMOD-)/t);
}
}
ll quick_pow(ll x,ll n){
ll ans=;
while(n){
if(n&)
ans=Mul(ans,x);
x=Mul(x,x);
n>>=;
}
return ans;
}
int get_len(int n){///计算刚好比n大的2的N次幂
int i,len;
for(i=(<<); i; i>>=){
if(n&i){
len=(i<<);
break;
}
}
return len;
}
inline void NTT(ll F[],int len,int type){
int id=,h,j,k,t,i;
ll E,u,v;
for(i=,t=; i<len; i++){///逆位置换
if(i>t) swap(F[i],F[t]);
for(j=(len>>); (t^=j)<j; j>>=);
}
for( h=; h<=len; h<<=){///层数
id++;
for( j=; j<len; j+=h){///遍历这层上的结点
E=;///旋转因子
for(int k=j; k<j+h/; k++){///遍历结点上的前半序列
u=F[k];///A[0]
v=Mul(E,F[k+h/]);///w*A[1]
///对偶计算
F[k]=(u+v)%PMOD;
F[k+h/]=((u-v)%PMOD+PMOD)%PMOD;
///迭代旋转因子
E=Mul(E,qp[id]);///qp[id]是2^i等分因子
}
}
}
if(type==-){
int i;
ll inv;
for(i=; i<len/; i++)///转置,因为逆变换时大家互乘了对立点的因子
swap(F[i],F[len-i]);
inv=quick_pow(len,PMOD-);///乘逆元还原
for( i=; i<len; i++)
F[i]=Mul(F[i],inv);
}
}
void mul(ll x[],ll y[],int len){///答案存在x中
int i;
NTT(x,len,);///先变换到点值式
NTT(y,len,);///先变换到点值式上
for(i=; i<len; i++)
x[i]=Mul(x[i],y[i]);///在点值上点积
NTT(x,len,-);///再逆变换回系数式
}
} cal;
ll a[N], b[N];
int main() {
int n;
scanf("%d",&n);
for(int i=;i<n;i++)
scanf("%lld",a+i), a[i+n]=a[i];
for(int i=;i<n;i++)
scanf("%lld",&b[n--i]);
int len=cal.get_len(n+n+n);
cal.mul(a, b, len);
ll mx=;
for(int i=;i<len;i++){///完整的组合肯定更大所以说直接找最大
if(mx<a[i]){
mx=a[i];
}
}
printf("%lld\n",mx);
return ;
}

时间:1036MS 内存: 23632KB

还有优化的解法,这我真不知道为什么,可能是因为前后相加刚好可以组合出全部组合:

 #include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll PMOD=(27ll<<)+, PR=;
const int N=1e6+;
static ll qp[];
ll res[N];
inline ll Mul(ll a,ll b){
if(a>=PMOD)a%=PMOD;
if(b>=PMOD)b%=PMOD;
//if(n<=1000000000)return a*b%n;
return (a*b-(ll)(a/(long double)PMOD*b+1e-)*PMOD+PMOD)%PMOD;
}
struct NTT__container{
NTT__container( ){
int t,i;
for(i=; i<; i++){///注意循环上界与2n次幂上界相同
t=<<i;
qp[i]=quick_pow(PR,(PMOD-)/t);
}
}
ll quick_pow(ll x,ll n){
ll ans=;
while(n){
if(n&)
ans=Mul(ans,x);
x=Mul(x,x);
n>>=;
}
return ans;
}
int get_len(const int &n){///计算刚好比n大的2的N次幂
int i, len;
for(i=(<<); i; i>>=){
if(n&i){
len=(i<<);break;
}
}
return len;
}
inline void NTT(ll F[], const int &len, int type){
int id=, h, j, t, i;
ll E,u,v;
for(i=,t=; i<len; i++){///逆位置换
if(i>t) swap(F[i],F[t]);
for(j=(len>>); (t^=j)<j; j>>=);
}
for( h=; h<=len; h<<=){///层数
id++;
for( j=; j<len; j+=h){///遍历这层上的结点
E=;///旋转因子
for(int k=j; k<j+h/; k++){///遍历结点上的前半序列
u=F[k];///A[0]
v=Mul(E,F[k+h/]);///w*A[1]
///对偶计算
F[k]=(u+v)%PMOD;
F[k+h/]=((u-v)%PMOD+PMOD)%PMOD;
///迭代旋转因子
E=Mul(E,qp[id]);///qp[id]是2^i等分因子
}
}
}
if(type==-){
int i;
ll inv;
for(i=; i<len/; i++)///转置,因为逆变换时大家互乘了对立点的因子
swap(F[i],F[len-i]);
inv=quick_pow(len,PMOD-);///乘逆元还原
for( i=; i<len; i++)
F[i]=Mul(F[i],inv);
}
}
void mul(ll x[],ll y[],int len){///答案存在x中
int i;
NTT(x,len,);///先变换到点值式
NTT(y,len,);///先变换到点值式上
for(i=; i<len; i++)
x[i]=Mul(x[i],y[i]);///在点值上点积
NTT(x,len,-);///再逆变换回系数式
}
} cal;
ll a[N], b[N];
int main() {
int n;
scanf("%d",&n);
for(int i=;i<n;i++)
scanf("%lld",a+i);
for(int i=;i<n;i++)
scanf("%lld",&b[n--i]);
int len=cal.get_len(n+n);
cal.mul(a, b, len);
ll mx=;
for(int i=;i<len;i++){
a[i]+=a[i+n];
if(mx<a[i]){
mx=a[i];
}
}
printf("%lld\n",mx);
return ;
}

时间:560MS 内存:23632KB

第八集:魔法阵 NTT求循环卷积的更多相关文章

  1. 【DFS】佳佳的魔法阵

    [vijos1284]佳佳的魔法阵 背景 也许是为了捕捉猎物(捕捉MM?),也许是因为其它原因,总之,佳佳准备设计一个魔法阵.而设计魔法阵涉及到的最关键问题,似乎就是那些带有魔力的宝石的摆放…… 描述 ...

  2. [NOIP2016普及组]魔法阵

    题目:洛谷P2119.Vijos P2012.codevs5624. 题目大意:有n件物品,每件物品有个魔法值.要求组成魔法阵(Xa,Xb,Xc,Xd),该魔法阵要满足Xa<Xb<Xc&l ...

  3. P2119 魔法阵

    原题链接  https://www.luogu.org/problemnew/show/P2119 YY同学今天上午给我们讲了这个题目,我觉得她的思路很好,特此写这篇博客整理一下. 50分:暴力枚举 ...

  4. 「Vijos 1284」「OIBH杯NOIP2006第二次模拟赛」佳佳的魔法阵

    佳佳的魔法阵 背景 也许是为了捕捉猎物(捕捉MM?),也许是因为其它原因,总之,佳佳准备设计一个魔法阵.而设计魔法阵涉及到的最关键问题,似乎就是那些带有魔力的宝石的摆放-- 描述 魔法阵是一个\(n ...

  5. 【做题记录】[NOIP2016 普及组] 魔法阵

    P2119 魔法阵 2016年普及组T4 题意: 给定一系列元素 \(\{X_i\}\) ,求满足以下不等式的每一个元素作为 \(a,b,c,d\) 的出现次数 . \[\begin{cases}X_ ...

  6. 洛谷 P2119 魔法阵

    题目描述 六十年一次的魔法战争就要开始了,大魔法师准备从附近的魔法场中汲取魔法能量. 大魔法师有mm个魔法物品,编号分别为1,2,...,m1,2,...,m.每个物品具有一个魔法值,我们用X_iXi ...

  7. [luogu2119]魔法阵 NOIP2016T4

    很好的一道数学推导题 45分做法 $O(N^4)$暴力枚举四个材料 55分做法 从第一个约束条件可得到所有可行答案都是单调递增的,所以可以排序一遍,减少枚举量,可以拿到55分 100分做法 首先可以发 ...

  8. ZOJ 3962 Seven Segment Display 16进制的八位数加n。求加的过程中所有的花费。显示[0,F]有相应花费。

    Seven Segment Display Time Limit: Seconds Memory Limit: KB A seven segment display, or seven segment ...

  9. 洛谷P2119 魔法阵

    P2119 魔法阵 题目描述 六十年一次的魔法战争就要开始了,大魔法师准备从附近的魔法场中汲取魔法能量. 大魔法师有m个魔法物品,编号分别为1,2,...,m.每个物品具有一个魔法值,我们用Xi表示编 ...

随机推荐

  1. Beta任务项录入

    今天PM把任务项整理写入TFS中,明天开始正式开发工作:

  2. mybatis 注解和xml 优缺点

    xml: 增加了xml文件,修改麻烦,条件不确定(ifelse判断),容易出错,特殊转义字符比如大于小于 注释: 复杂sql不好用,搜集sql不方便,管理不方便,修改需重新编译 #和$区别: 相同 都 ...

  3. idea中 读取mybatis的配置文件时候 如果放在文件下面 需要加上路径

  4. BZOJ3434 WC2014时空穿梭(莫比乌斯反演)

    考虑枚举相邻点距离差的比例.显然应使比例值gcd为1以保证不重复统计.确定比例之后,各维坐标的方案数就可以分开考虑.设比例之和为k,则若坐标上限为m,该维坐标取值方案数即为Σm-ki (i=1~⌊m/ ...

  5. Luogu4980 【模板】Polya定理(Polya定理+欧拉函数)

    对于置换0→i,1→i+1……,其中包含0的循环的元素个数显然是n/gcd(i,n),由对称性,循环节个数即为gcd(i,n). 那么要求的即为Σngcd(i,n)/n(i=0~n-1,也即1~n). ...

  6. BZOJ2326 HNOI2011数学作业(矩阵快速幂)

    考虑暴力,那么有f(n)=(f(n-1)*10digit+n)%m.注意到每次转移是类似的,考虑矩阵快速幂.首先对于位数不同的数字分开处理,显然这只有log种.然后就得到了f(n)=a·f(n-1)+ ...

  7. BZOJ1050 HAOI2006旅行(最小生成树+LCT)

    暴力枚举路径中权值最小边是哪个,然后求出边权不小于它的边的最小生成树,即可保证该路径上最大值最小.暴力当然可以过,这里使用LCT维护.注意数据中有自环. #include<iostream> ...

  8. POJ 2584 T-Shirt Gumbo

    T-Shirt Gumbo Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3689   Accepted: 1755 Des ...

  9. 【刷题】BZOJ 2194 快速傅立叶之二

    Description 请计算C[k]=sigma(a[i]*b[i-k]) 其中 k < = i < n ,并且有 n < = 10 ^ 5. a,b中的元素均为小于等于100的非 ...

  10. 【CF888E】Maximum Subsequence(meet in the middle)

    [CF888E]Maximum Subsequence(meet in the middle) 题面 CF 洛谷 题解 把所有数分一下,然后\(meet\ in\ the\ middle\)做就好了. ...