(每日一题)2016 北京ICPC网络赛G hihocoder 1388 (中国剩余定理 + NTT)

Posted 繁凡さん

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(每日一题)2016 北京ICPC网络赛G hihocoder 1388 (中国剩余定理 + NTT)相关的知识,希望对你有一定的参考价值。

整理的算法模板合集: ACM模板

点我看算法全家桶系列!!!

实际上是一个全新的精炼模板整合计划


Weblink

https://vjudge.net/problem/HihoCoder-1388

Problem

给定数组 A A A 和数组 B B B,求:

m i n { ∑ i = 0 n − 1 ( A i − B ( i + k )   m o d   n ) 2   ∣   k = 0 , 1 … n − 1 } min \\left\\{ \\sum_{i=0}^{n-1}(A_i-B_{(i+k) \\space mod \\space n})^2\\ \\big | \\ k=0,1\\dots n-1 \\right\\} min{i=0n1(AiB(i+k) mod n)2  k=0,1n1}

Solution

将式子展开:

m i n { ∑ i = 0 n − 1 ( A i − B ( i + k ) m o d    n ) 2   ∣   k = 0 , 1 … n − 1 } = ∑ i = 0 n − 1 A i 2 + ( B ( i + k ) m o d    n ) 2 + 2 × A i × B ( i + k ) m o d    n = ∑ i = 0 n − 1 A i 2 + ∑ i = 0 n − 1 B i 2 + ∑ i = 0 n − 1 2 × A i × B ( i + k ) m o d    n \\begin{aligned} & min \\left\\{ \\sum_{i=0}^{n-1}(A_i-B_{(i+k) \\mod n})^2\\ \\big | \\ k=0,1\\dots n-1 \\right\\}& \\\\ &= \\sum_{i=0}^{n-1}A_i^2+(B_{(i+k) \\mod n})^2+2\\times A_i\\times B_{(i+k) \\mod n}& \\\\ &= \\sum_{i=0}^{n-1}A_i^2+ \\sum_{i=0}^{n-1}B_i^2+ \\sum_{i=0}^{n-1}2\\times A_i\\times B_{(i+k) \\mod n} \\end{aligned} min{i=0n1(AiB(i+k)modn)2  k=0,1n1}=i=0n1Ai2+(B(i+k)modn)2+2×Ai×B(i+k)modn=i=0n1Ai2+i=0n1Bi2+i=0n12×Ai×B(i+k)modn

显然前面两个都是定值,我们只需要求 2 × ∑ i = 0 n − 1 A i × B ( i + k ) m o d    n \\displaystyle2\\times \\sum_{i=0}^{n-1} A_i\\times B_{(i+k) \\mod n} 2×i=0n1Ai×B(i+k)modn 的最小值即可。

经典将 B 数组翻转,然后倍长,这样就是卷积的形式了,我们就可以直接卷了。

然后因为数据较大,FFT 精度不够,并且题目中还没有给模数,可以找两个大模数直接NTT,然后 CRT 合并即可。

模数我选的 1 0 9 10^9 109 ,中间记得用龟速乘,不然会爆 long long

Code

(原题的OJ炸了,反正样例过了就是过了(doge))

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

const int N = 1000007, G = 3;
const ll mod1 = 1004535809, mod2 = 998244353;

ll M;
int n, m;
ll a[N], b[N];
ll f1[N], f2[N], g1[N], g2[N];
int limit, L;
int RR[N];
  
ll mul(ll a, ll b, ll mod)
{
	ll res = 0;
	while(b) {
		if(b & 1) res = res + a % mod;
		a = a + a % mod;
		b >>= 1;
	}
	return res;
}

ll qpow(ll a, ll b, ll mod)
{
	ll res = 1;
	while(b) {
		if(b & 1) res = res * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return res;
}

ll inv(ll x, ll mod)
{
	return qpow(x, mod - 2, mod);
}

ll exgcd(ll a, ll b, ll &x, ll &y)
{
	if(b == 0) {
		x = 1, y = 0;
		return a;
	}
	ll d = exgcd(b, a % b, x, y);
	ll z = x;
	x = y;
	y = z - y * (a / b);
	return d;
}

ll mm[5], aa[5];
  
ll CRT(int n, ll *a, ll *mo)
{
	M = mo[1] * mo[0];
    ll res = 0;
    for(ll i = 0; i < n; ++ i) {
        ll Mi = M / mo[i];
        ll ti, y;
        ll d = exgcd(Mi, mo[i], ti, y);
        ti = (ti % mo[i] + mo[i]) % mo[i];
        res = (res + mul(mul(a[i], ti, M), Mi, M)) % M;
    }
    return (res % M + M) % M;
} 

void NTT(ll *A, int type, ll mod)
{
	for(int i = 0; i < limit; ++ i)
		if(i < RR[i])
			swap(A[i], A[RR[i]]); 

	for(int mid = 1; mid < limit; mid <<= 1) {
		ll wn = qpow(G, (mod - 1) / (mid * 2), mod);
		if(type == -1)
			wn = qpow(wn, mod - 2, mod);
		for(int len = mid << 1, pos = 0; pos < limit; pos += len) {
			ll w = 1;
			for(int k = 0; k < mid; ++ k, w = (w * wn) % mod) {
				ll x = A[pos + k], y = w * A[pos + mid + k] % mod;
				A[pos + k] = (x + y) % mod;
				A[pos + k + mid] = (x - y + mod) % mod;
			}
		}
	}
	if(type == -1) {
		ll limit_inv = inv(limit, mod);
		for(int i = 0; i < limit; ++ i)
			A[i] = (A[i] * limit_inv) % mod;
	}
}
 

void solve()
{
	scanfACM-ICPC国际大学生程序设计竞赛北京赛区(2016)网络赛 The Book List

hihoCoder 1389 Sewage Treatment 二分+网络流+优化 (ACM-ICPC国际大学生程序设计竞赛北京赛区(2016)网络赛)

hihoCoder 1392 War Chess 模拟 (ACM-ICPC国际大学生程序设计竞赛北京赛区(2016)网络赛)

hihoCoder 1391 Countries 预处理+排序+堆 (ACM-ICPC国际大学生程序设计竞赛北京赛区(2016)网络赛)

icpc 2018 北京网络赛 A(搜索)

2019 ICPC 南昌网络赛