第八集:魔法阵 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表示编 ...
随机推荐
- Daily Scrum 12.22
姓名 上周末任务 今日任务 刘垚鹏 完善和增加quiz页面的过滤功能 完善和增加quiz页面的过滤功能 王骜 对问答功能的修复 对问答功能的修复 林旭鹏 存储文件路径太长导致bug修复 存储文件路径太 ...
- 2-Sixteenth Scrum Meeting-20151216
任务安排 成员 今日完成 明日任务 闫昊 写完学习进度记录的数据库操作 写完学习进度记录的数据库操作 唐彬 编写与服务器交互的代码 编写与服务器交互的代码 史烨轩 获取视频url 余帆 本地 ...
- 第二阶段Sprint7
昨天:将“录制”及“保存”整合到一起,修复出现的Bug,使之能够正常运行. 今天:把视频录制整合到时间提醒里,实现视频提醒 遇到的问题:额,整进去直接就停止运行了..也没有报错..
- PAT 甲级 1085 Perfect Sequence
https://pintia.cn/problem-sets/994805342720868352/problems/994805381845336064 Given a sequence of po ...
- WM_CONCAT和LISTAGG 语法例子
select to_char(replace(wm_concat(name), ',', '')) from codeitems where setid = 'A018' and ' like cod ...
- RANCHER2.0 的简单使用
1. RANCHER2.0 能够管理 k8s 集群 也能够用来搭建 k8s 集群 但是因为网络问题 只测试了如何去管理集群 还没有去 测试 安装集群. 2. 创建rancher 服务的方法 dock ...
- PSP(3.16——3.22)以及周记录
3.17 13:30 14:45 15 60 讨论班 A Y min 14:50 17:05 5 130 得到设备 Cordova 蓝牙连接 A Y min 23:15 23:45 5 25 英语百词 ...
- 以太坊 链私有链环境搭建(windows)
摸索以太坊区块链技术几个月了.最近打算逐步的把自己学到的东西和大家分享一下.在阅读本文之前,希望大家能对区块链的概念能有所了解.这样操作过程中的环节理解更深入.下面开始进入准备.因为本次是window ...
- 安利一个很火的 Github 滤镜项目
安利一个很火的 Github 滤镜项目 园长 1 个月前 简评:通过深度学习,一秒钟让你的照片高大上,这是康奈尔大学和 Adobe 的工程师合作的一个新项目,通过卷积神经网络把图片进行风格迁移.项目已 ...
- POJ 1797 Heavy Transportation / SCU 1819 Heavy Transportation (图论,最短路径)
POJ 1797 Heavy Transportation / SCU 1819 Heavy Transportation (图论,最短路径) Description Background Hugo ...