• Luogu6300 悔改 [FFT,阈值法]


    题目描述:小 D 有一些同样长的木棍,然后每个都切成长度分别不超过 (m) 的两段。现在想拼回去,但是小 D 遗失了一部分木棍,而且还忘了它们的长度和个数,所以他想拼接出尽可能多的相同长度的木棍。给出每段小木棍的长度,求尽可能多的木棍个数和此时的木棍最小长度。

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


    开桶 ({b_m})

    [egin{aligned} Ans_x&=frac12sum_{i+j=x}min(b_i,b_j) \ &=sum_ksum_{i+j=x}[b_ige k][b_jge k] end{aligned} ]

    使用 FFT,成功得到了一个 (O(nmlog m)) 的比暴力还lj的做法。

    但是你发现 (sum b_i=nle 10^5),所以你可以"阈值法"(?),定一个数 (t),当 (kle t) 时用 FFT 计算,(b_i>t) 的数不超过 (frac nt) 个,所以时间复杂度是 (O(tmlog m+(frac nt)^2))

    我不会算函数最值,纯粹喜欢 (t=10) 而已(太草了)

    #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
    ", f[ans] >> 1, ans);
    }
    
  • 相关阅读:
    Atitit.安全性方案规划设计4gm  v1 q928
    Atitit ati licenseService    设计原理
    Atitit.js图表控件总结
    Atitit. null错误的设计 使用Optional来处理null
    System.Web.Mvc 命名空间
    provider: SQL Network Interfaces, error: 26 Error Locating Server/Instance Specified
    Visual Studio 2010 实用功能总结
    My First J2ME
    Java开发利器ideaIU最新版本10.5的keygen
    Happy New Year for 2012
  • 原文地址:https://www.cnblogs.com/AThousandMoons/p/12675694.html
Copyright © 2020-2023  润新知