Luogu6300 Repentance [FFT, threshold method]

Title Description: Little D has some wooden sticks of the same length, and then each is cut into two sections with a length not exceeding \ (m \) . Now he wants to fight back, but Xiao D has lost some of the sticks, and has forgotten their length and number, so he wants to stitch together as many sticks of the same length as possible. Given the length of each small stick, find as many sticks as possible and the minimum length of sticks at this time.

数据 范围 :\ (2 \ le n, m \ le 10 ^ 5,1 \ le a_i \ le m \)


Open the bucket \ (\ {b_m \} \)

\[\begin{aligned} Ans_x&=\frac12\sum_{i+j=x}\min(b_i,b_j) \\ &=\sum_k\sum_{i+j=x}[b_i\ge k][b_j\ge k] \end{aligned} \]

Using FFT, I successfully got a \ (O (nm \ log m) \) method that is more violent than lj.

But you found \ (\ sum b_i = n \ le 10 ^ 5 \) , so you can "threshold method" (?), Set a number \ (t \) , use FFT when \ (k \ le t \) Calculated, the number of \ (b_i> t \) does not exceed \ (\ frac nt \) , so the time complexity is \ (O (tm \ log m + (\ frac nt) ^ 2) \) .

I would not count function most value, pure love \ (t = 10 \) it (the grass too) .

#include<bits/stdc++.h>
#define Rint register int
using namespace std;
const int N = 1 << 18, B = 10;
const double PI = acos(-1);
int n, m, a[N], b[N], tot, f[N], now, ans;
template<typename T>
inline void read(T &x){
    int ch = getchar(); x = 0;
    for(;ch < '0' || ch > '9';ch = getchar());
    for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
}
struct comp {
	double x, y;
	inline comp(double _x = 0, double _y = 0): x(_x), y(_y){}
	inline comp operator + (const comp &o) const {return comp(x + o.x, y + o.y);}
	inline comp operator * (const comp &o) const {return comp(x * o.x - y * o.y, x * o.y + y * o.x);}
	inline comp operator - (const comp &o) const {return comp(x - o.x, y - o.y);}
	inline comp operator ~ () const {return comp(x, -y);}
} w[2][N], A[N];
int rev[N], lim;
inline void calrev(int len){
	int L = -1; lim = 1;
	while(lim <= len){lim <<= 1; ++ L;}
	for(Rint i = 0;i < lim;++ i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << L);
	for(Rint mid = 1;mid < lim;mid <<= 1)
		for(Rint i = 0;i < mid;++ i) w[1][mid + i] = ~(w[0][mid + i] = comp(cos(PI / mid * i), sin(PI / mid * i)));
}
void FFT(comp *A, int op){
	for(Rint i = 0;i < lim;++ i)
		if(i < rev[i]) swap(A[i], A[rev[i]]);
	for(Rint mid = 1;mid < lim;mid <<= 1)
		for(Rint j = 0;j < lim;j += mid << 1)
			for(Rint k = 0;k < mid;++ k){
				comp x = A[j + k], y = A[j + k + mid] * w[op][mid + k];
				A[j + k] = x + y; A[j + k + mid] = x - y;
			}
	if(op) for(Rint i = 0;i < lim;++ i) A[i].x /= lim;
}
int main(){
	read(n); read(m); now = m; calrev(m << 1);
	for(Rint i = 1, x;i <= n;++ i) read(x), ++ a[x];
	for(Rint t = 1;t <= B;++ t){
		memset(A, 0, sizeof A);
		for(Rint i = 1;i <= m;++ i) A[i].x = a[i] >= t;
		FFT(A, 0); for(Rint i = 0;i < lim;++ i) A[i] = A[i] * A[i]; FFT(A, 1);
		for(Rint i = 1;i <= (m << 1);++ i) f[i] += A[i].x + .5;
	}
	for(Rint i = 1;i <= m;++ i){
		a[i] -= B;
		if(a[i] > 0) b[++ tot] = i;
	}
	for(Rint i = 1;i <= tot;++ i)
		for(Rint j = 1;j <= tot;++ j) f[b[i] + b[j]] += min(a[b[i]], a[b[j]]);
	for(Rint i = 1;i <= (m << 1);++ i) if(f[i] > f[ans]) ans = i;
	printf("%d %d\n", f[ans] >> 1, ans);
}

Guess you like

Origin www.cnblogs.com/AThousandMoons/p/12675694.html
FFT