fjut3283(NTT快速数论变换)

题解:我们将B序列反转那么最后就会变成

a0,a1,a2,.....an-1

b0,a1,b2......bn-1

那么答案将变成a0*bi+a1*bi-1+.....ai*b0+...+ai+1*bn-1+ai+2*bn-2+....an-1*bi+1然后你会发现答案就是多项式乘法,指数相加等于i的系数加上指数相加等于i+n的系数就是答案,因为这题数值较大用FFT可能会精度出现问题所以我们选用NTT算法,接着就是取P和原根了,因为我们这里最大的数值可能是1e17所以我们选择5*2^55+1作为P,然后他的原根是6,多项式乘法后枚举每个i后取最大值即可

按平时选择998244353原根是3即可

这里有个费马素数表来自大佬的博客:https://blog.csdn.net/hnust_xx/article/details/76572828

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstdio>
#include<cmath>
#include<set>
#include<map>
#include<complex>
#include<cstdlib>
#include<ctime>
#include<stack>
#include<bitset>
using namespace std;
#define mes(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define dec(i,a,b) for(int i = a; i >= b; i--)
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define ls rt<<1
#define rs rt<<1|1
#define lson ls,L,mid
#define rson rs,mid+1,R
#define lowbit(x) x&(-x)
typedef double db;
typedef long long int ll;
typedef pair<int,int> pii;
typedef complex<double> cd;
typedef unsigned long long ull;
const ll inf = 0x3f3f3f3f;
const int mx = 3e5+5;
const int mod = 1e9+7;
const ll P = 180143985094819841;
const int x_move[] = {1,-1,0,0,1,1,-1,-1};
const int y_move[] = {0,0,1,-1,1,-1,1,-1};
int n,m;
ll a[mx];
ll b[mx];
int rev[mx];
int bit;
int len;
void init(){
	for(int i = 0; i < len; i++)
		rev[i] = (rev[i>>1]>>1)|((i&1)<<bit-1);
}
ll modadd(ll x,ll n){
	ll ans = 0;
	__int128 a = x;
	__int128 b = n;
	ans = a*b%P;
	return ans;
}
ll modexp(ll x,ll n){
	ll ans = 1;
	while(n){
		if(n&1) ans = modadd(x,ans);
		x = modadd(x,x);
		n /= 2;
	}
	return ans;
}
void ntt(ll p[],int len,int dft){
	for(int i = 0; i < len; i++) if(i<rev[i]) swap(p[i],p[rev[i]]);
	for(int i = 1; i < len; i<<=1){
		ll wn = modexp(6,(P-1)/i/2);
		if(dft==-1)
			wn = modexp(wn,P-2);
		for(int j = 0; j < len; j += i<<1){		
			ll wnk = 1;
			for(int k = j; k < j+i; k++){
				ll x = p[k];
				ll y = modadd(p[k+i],wnk);
				p[k] = (x+y)%P;
				p[k+i] = (x-y+P)%P;
				wnk = modadd(wn,wnk);
			}
		}
	}
	if(dft==-1){
		ll inv = modexp(len,P-2);
		for(int i = 0; i < len; i++) p[i] = modadd(inv,p[i]);
	}
}
int main(){
	//freopen("test.in","r",stdin);
	//freopen("test.out","w",stdout);
	int t,q,ca = 1;
	scanf("%d",&n)	;
	for(int i = 0; i < n; i++)
		scanf("%lld",&a[i]);
	for(int i = 0; i < n; i++)
		scanf("%lld",&b[i]);
	reverse(b,b+n);
	while((1<<bit)<2*n-1) bit++;
	len = 1<<bit;
	init();
	ntt(a,len,1);
	ntt(b,len,1);
	for(int i = 0; i < len; i++) a[i] = modadd(a[i],b[i]);
	ntt(a,len,-1);
	ll ans = 0;
	for(int i = 0; i < n; i++)
		ans = max(ans,a[i]+a[n+i]);
	printf("%lld\n",ans);
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值