题意
传送门 TopCoder 12910 SumOfArrays
题解
将数组表示 a , b , c a,b,c a,b,c,令 A , B , C A,B,C A,B,C 表示数组不同值出现的次数。暴力求解 O ( n 2 ) O(n^2) O(n2)。
C k = ∑ i min ( A i , B k − i ) = ∑ i ∑ j = 1 ∞ [ A i ≥ j ] [ B k − i ≥ j ] C_k = \sum\limits_i \min (A_i, B_{k-i}) = \sum_i \sum\limits_{j=1}^{\infty}[A_i\geq j][B_{k-i}\geq j] Ck=i∑min(Ai,Bk−i)=i∑j=1∑∞[Ai≥j][Bk−i≥j] 后一个式子是卷积的形式。将 n n n 个小球随机放入 n n n 个盒子,那么单个盒子中最多的小球数期望为 m = O ( log n / log log n ) m = O(\log n/ \log\log n) m=O(logn/loglogn),即 C C C 中出现次数最多的数字,其出现次数期望为 m m m。将上式拆开 C k = ∑ j = 1 m ∑ i [ A i ≥ j ] [ B k − i ≥ j ] + ∑ j = m + 1 ∞ ∑ i [ A i ≥ j ] [ B k − i ≥ j ] C_k = \sum\limits_{j=1}^{m}\sum_i [A_i\geq j][B_{k-i}\geq j] + \sum\limits_{j=m+1}^{\infty}\sum_i [A_i\geq j][B_{k-i}\geq j] Ck=j=1∑mi∑[Ai≥j][Bk−i≥j]+j=m+1∑∞i∑[Ai≥j][Bk−i≥j] 后一个暴力算即可。总时间复杂度 O ( n log 2 n / log log n ) O(n\log^2 n/ \log\log n) O(nlog2n/loglogn)。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr ll MOD = 998244353, PRT = 3;
ll qpow(ll x, ll n)
{
ll res = 1;
while (n > 0)
{
if (n & 1)
res = res * x % MOD;
x = x * x % MOD, n >>= 1;
}
return res;
}
vector<int> rev;
struct Poly : vector<ll>
{
Poly() {}
Poly(int n) : vector<ll>(n) {}
Poly(const initializer_list<ll> &list) : vector<ll>(list) {}
void fft(int n, bool inverse)
{
if ((int)rev.size() != n)
{
rev.resize(n);
for (int i = 0; i < n; ++i)
rev[i] = rev[i >> 1] >> 1 | (i & 1 ? n >> 1 : 0);
}
resize(n);
for (int i = 0; i < n; ++i)
if (i < rev[i])
std::swap(at(i), at(rev[i]));
for (int m = 1; m < n; m <<= 1)
{
int m2 = m << 1;
ll _w = qpow(inverse ? qpow(PRT, MOD - 2) : PRT, (MOD - 1) / m2);
for (int i = 0; i < n; i += m2)
for (int w = 1, j = 0; j < m; ++j, w = w * _w % MOD)
{
ll &x = at(i + j), &y = at(i + j + m), t = w * y % MOD;
y = x - t;
if (y < 0)
y += MOD;
x += t;
if (x >= MOD)
x -= MOD;
}
}
}
void dft(int n) { fft(n, 0); };
void idft(int n)
{
fft(n, 1);
for (int i = 0, inv = qpow(n, MOD - 2); i < n; ++i)
at(i) = at(i) * inv % MOD;
}
Poly operator*(const Poly &p) const
{
auto a = *this, b = p;
int k = 1, n = a.size() + b.size() - 1;
while (k < n)
k <<= 1;
a.dft(k), b.dft(k);
for (int i = 0; i < k; ++i)
a[i] = a[i] * b[i] % MOD;
a.idft(k);
a.resize(n);
return a;
}
};
class SumOfArrays
{
public:
void get(vector<int> &a, vector<int> &A)
{
a[0] = A[0], a[1] = A[1];
for (int i = 2; i < a.size(); ++i)
a[i] = ((ll)a[i - 1] * A[2] + (ll)a[i - 2] * A[3] + A[4]) % A[5];
}
string findbestpair(int n, vector<int> A, vector<int> &B)
{
vector<int> a(n), b(n);
get(a, A), get(b, B);
vector<int> acnt(A[5]), bcnt(B[5]);
for (int i = 0; i < n; ++i)
++acnt[a[i]], ++bcnt[b[i]];
int m = 2 * ceil(log(n) / log(log(n)));
vector<int> cnt(A[5] + B[5]);
for (int num = 1; num <= m; ++num)
{
Poly f(A[5]), g(B[5]);
for (int i = 0; i < A[5]; ++i)
f[i] = acnt[i] >= num;
for (int i = 0; i < B[5]; ++i)
g[i] = bcnt[i] >= num;
f = f * g;
for (int i = 0; i < f.size(); ++i)
cnt[i] += f[i];
}
vector<int> ta, tb;
for (int i = 0; i < A[5]; ++i)
if (acnt[i] > m)
ta.push_back(i);
for (int i = 0; i < B[5]; ++i)
if (bcnt[i] > m)
tb.push_back(i);
for (int x : ta)
for (int y : tb)
cnt[x + y] += min(acnt[x], bcnt[y]) - m;
int _num = -1, _cnt = -1;
for (int i = 0; i < cnt.size(); ++i)
if (cnt[i] >= _cnt)
_cnt = cnt[i], _num = i;
return to_string(_cnt) + " " + to_string(_num);
}
};