第八集:魔法阵 NTT求循环卷积
题目来源: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求循环卷积的更多相关文章
- 【DFS】佳佳的魔法阵
[vijos1284]佳佳的魔法阵 背景 也许是为了捕捉猎物(捕捉MM?),也许是因为其它原因,总之,佳佳准备设计一个魔法阵.而设计魔法阵涉及到的最关键问题,似乎就是那些带有魔力的宝石的摆放…… 描述 ...
- [NOIP2016普及组]魔法阵
题目:洛谷P2119.Vijos P2012.codevs5624. 题目大意:有n件物品,每件物品有个魔法值.要求组成魔法阵(Xa,Xb,Xc,Xd),该魔法阵要满足Xa<Xb<Xc&l ...
- P2119 魔法阵
原题链接 https://www.luogu.org/problemnew/show/P2119 YY同学今天上午给我们讲了这个题目,我觉得她的思路很好,特此写这篇博客整理一下. 50分:暴力枚举 ...
- 「Vijos 1284」「OIBH杯NOIP2006第二次模拟赛」佳佳的魔法阵
佳佳的魔法阵 背景 也许是为了捕捉猎物(捕捉MM?),也许是因为其它原因,总之,佳佳准备设计一个魔法阵.而设计魔法阵涉及到的最关键问题,似乎就是那些带有魔力的宝石的摆放-- 描述 魔法阵是一个\(n ...
- 【做题记录】[NOIP2016 普及组] 魔法阵
P2119 魔法阵 2016年普及组T4 题意: 给定一系列元素 \(\{X_i\}\) ,求满足以下不等式的每一个元素作为 \(a,b,c,d\) 的出现次数 . \[\begin{cases}X_ ...
- 洛谷 P2119 魔法阵
题目描述 六十年一次的魔法战争就要开始了,大魔法师准备从附近的魔法场中汲取魔法能量. 大魔法师有mm个魔法物品,编号分别为1,2,...,m1,2,...,m.每个物品具有一个魔法值,我们用X_iXi ...
- [luogu2119]魔法阵 NOIP2016T4
很好的一道数学推导题 45分做法 $O(N^4)$暴力枚举四个材料 55分做法 从第一个约束条件可得到所有可行答案都是单调递增的,所以可以排序一遍,减少枚举量,可以拿到55分 100分做法 首先可以发 ...
- 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 ...
- 洛谷P2119 魔法阵
P2119 魔法阵 题目描述 六十年一次的魔法战争就要开始了,大魔法师准备从附近的魔法场中汲取魔法能量. 大魔法师有m个魔法物品,编号分别为1,2,...,m.每个物品具有一个魔法值,我们用Xi表示编 ...
随机推荐
- RYU 的选择以及安装
RYU 的选择以及安装 由于近期的项目需求,不得已得了解一下控制器内部发现拓扑原理,由于某某应用中的控制器介绍中使用的RYU,所以打算把RYU装一下试试.出乎意料的是,RYU竟是我之前装过最最轻便的控 ...
- 分析code
1 using System; //跟系统说明一下可能会用到这个dll里面的东西 using System.Collections.Generic; //引用集合类命名空间 using System. ...
- Beta冲刺——day4
Beta冲刺--day4 作业链接 Beta冲刺随笔集 github地址 团队成员 031602636 许舒玲(队长) 031602237 吴杰婷 031602220 雷博浩 031602134 王龙 ...
- phaser3 微信小游戏入门
phaser与eget, laya, pixi.js本质上没什么区别. 都是渲染引擎. 其它的都是配角. phaser的特点是.代码容易理解 功能比较全面. 个人比较喜欢phaser的地方 twe ...
- Ubuntu17安装maven3.5.2
1.下载maven 源码文件.tar.gz 2.解压源文件sudo tar -zxvf .tar.gz文件 3.配置/etc/profile文件 export MAVEN_HOME=/app/java ...
- Spring之配置文件中引入其它配置文件
<beans> ... <!--引入其它配置文件--> <import resource="classpath:com/helloworld/beans.xml ...
- C#快速删除bin和obj文件夹的方法
C#程序总会生成bin和obj文件夹,为了减小源码的大小,就有必要将这两个文件夹删除,于是想到用批处理文件来删除. 以下是批处理的代码: @echo offset nowPath=%cd%cd /cd ...
- 一本通1641【例 1】矩阵 A×B
1641: [例 1]矩阵 A×B sol:矩阵乘法模板.三个for循环 #include <bits/stdc++.h> using namespace std; typedef lon ...
- HGOI 20181103 题解
problem:把一个可重集分成两个互异的不为空集合,两个集合里面的数相乘的gcd为1(将集合中所有元素的质因数没有交集) solution:显然本题并不是那么容易啊!考场上想了好久.. 其实转化为上 ...
- 前端学习 -- Css -- 有序列表和无序列表
列表就相当于去超市购物时的那个购物清单, 在HTML也可以创建列表,在网页中一共有三种列表: 1.无序列表 2.有序列表 3.定义列表 无序列表 - 使用ul标签来创建一个无序列表 - 使用li在ul ...