zoukankan      html  css  js  c++  java
  • @topcoder


    @desription@

    给定两个长度为 n 的数列 A, B。现你可以将两数列重排列,然后对应项相加得到 C[i] = A[i] + B[i]。

    问你所能构造的 C 中众数的最大出现次数,以及此时的众数。如果有多种方案,取最大的众数。

    原题传送门。

    @solution@

    (cnta[i]) 表示 (i) 在 A 中的出现次数,(cntb[i]) 表示 (i) 在 B 中的出现次数。则 p 在 C 中的最大出现次数为 (sum_{i=0}^{p}min(cnta[i], cntb[p-i]))

    注意到它长得特别像个卷积。我们记 (Fa_i(x) = sum_{p=0}^{MAX} [cnta[p] = i]x^{p}),同理记 (Fb_i(x) = sum_{p=0}^{MAX} [cntb[p] = i]x^p)。则答案:

    [G(x) = sum_{i=1}^{n}i imes (Fa_i(x)(sum_{j=i+1}^{n} Fb_j(x)) + Fb_i(x)(sum_{j=i+1}^{n} Fa_j(x)) + Fa_i(x) Fb_i(x)) ]

    不过这样算还不如暴力快。

    注意到 (sum cnta[i] = n),也就是说如果 i 越大,满足 cnta[p] = i 的 p 会越少。
    具体而言,A 中 cnta[p] ≥ K 有 (O(frac{n}{K})) 个,B 中也有 (O(frac{n}{K}))。那么我们可以枚举每一个可能的二元组暴力计算,时间复杂度为 (O(frac{n^2}{K^2}))
    当 K 较大时,这个暴力算法相对于上面的卷积方法而言,其实是非常快的。

    于是又到了喜闻乐见的复杂度平衡时间:对于 i < K,使用卷积计算,复杂度为 (O(K imes MAX imes log MAX));对于 i >= K,使用暴力枚举,复杂度为 (O(frac{n^2}{K^2}))
    因为 n 与 MAX 同阶,我们直接令 (Knlog n = frac{n^2}{K^2}),解得 (K = (frac{n}{log n})^{frac{1}{3}})

    然后总时间复杂度 (O(n^{frac{4}{3}} imes log^{frac{2}{3}}n )),虽然看着挺糟不过其实挺优秀的。

    @accepted code@

    #include <cstdio>
    #include <vector>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int MOD = 998244353;
    const int MAXN = (1 << 17);
    const int K = 18;
    const int G = 3;
    
    inline int add(int x, int y) {return (x + y >= MOD ? x + y - MOD : x + y);}
    inline int sub(int x, int y) {return (x - y < 0 ? x - y + MOD : x - y);}
    inline int mul(int x, int y) {return 1LL * x * y % MOD;}
    
    int pow_mod(int b, int p) {
    	int ret = 1;
    	for(int i=p;i;i>>=1,b=mul(b,b))
    		if( i & 1 ) ret = mul(ret, b);
    	return ret;
    }
    
    int w[22], iw[22];
    void init() {
    	for(int i=0;i<22;i++) {
    		w[i] = pow_mod(G, (MOD - 1) / (1 << i));
    		iw[i] = pow_mod(w[i], MOD - 2);
    	}
    }
    int length(int n) {
    	int len; for(len = 1; len < n; len <<= 1);
    	return len;
    }
    void ntt(int *A, int n, int type) {
    	for(int i=0,j=0;i<n;i++) {
    		if( i < j ) swap(A[i], A[j]);
    		for(int k=(n>>1);(j^=k)<k;k>>=1);
    	}
    	for(int i=1;(1<<i)<=n;i++) {
    		int s = (1 << i), t = (s >> 1);
    		int u = (type == 1 ? w[i] : iw[i]);
    		for(int j=0;j<n;j+=s) {
    			for(int k=0,p=1;k<t;k++,p=mul(p,u)) {
    				int x = A[j+k], y = mul(p, A[j+k+t]);
    				A[j+k] = add(x, y), A[j+k+t] = sub(x, y);
    			}
    		}
    	}
    	if( type == -1 ) {
    		int iv = pow_mod(n, MOD - 2);
    		for(int i=0;i<n;i++)
    			A[i] = mul(A[i], iv);
    	}
    }
    
    class SumOfArrays{
    	public:
    		vector<pair<int, int> >na, nb;
    		int f[2*MAXN + 5];
    		int ca[MAXN + 5], cb[MAXN + 5];
    		int a[MAXN + 5], b[MAXN + 5];
    		int ta1[2*MAXN + 5], ta2[2*MAXN + 5], tb1[2*MAXN + 5], tb2[2*MAXN + 5], tmp[2*MAXN + 5];
    		string findbestpair(int n, vector<int>A, vector<int>B) {
    			init();
    			a[0] = A[0], a[1] = A[1], b[0] = B[0], b[1] = B[1];
    			for(int i=2;i<n;i++) {
    				a[i] = (1LL*A[2]*a[i-1]%A[5] + 1LL*A[3]*a[i-2]%A[5] + A[4]) % A[5];
    				b[i] = (1LL*B[2]*b[i-1]%B[5] + 1LL*B[3]*b[i-2]%B[5] + B[4]) % B[5];
    			}
    			for(int i=0;i<n;i++)
    				ca[a[i]]++, cb[b[i]]++;
    			for(int i=0;i<MAXN;i++) {
    				if( ca[i] >= K ) na.push_back(make_pair(i, ca[i]));
    				if( cb[i] >= K ) nb.push_back(make_pair(i, cb[i]));
    			}
    			for(int i=0;i<(int)na.size();i++)
    				for(int j=0;j<(int)nb.size();j++)
    					f[na[i].first + nb[j].first] += min(na[i].second, nb[j].second);
    			for(int i=1;i<K;i++) {
    				bool flag = false;
    				for(int j=0;j<MAXN;j++) {
    					if( ca[j] > i ) ta1[j]++;
    					else if( ca[j] == i ) ta2[j]++, flag = true;
    					
    					if( cb[j] > i ) tb1[j]++;
    					else if( cb[j] == i ) tb2[j]++, flag = true;
    				}
    				int len = 2*MAXN;
    				if( flag ) {
    					ntt(ta1, len, 1), ntt(ta2, len, 1), ntt(tb1, len, 1), ntt(tb2, len, 1);
    					for(int j=0;j<len;j++)
    						tmp[j] = add(add(mul(ta1[j], tb2[j]), mul(ta2[j], tb1[j])), mul(ta2[j], tb2[j]));
    					ntt(tmp, len, -1);
    					for(int j=0;j<len;j++)
    						f[j] = add(f[j], mul(tmp[j], i));
    				}
    				for(int j=0;j<len;j++) ta1[j] = ta2[j] = tb1[j] = tb2[j] = tmp[j] = 0;
    			}
    			
    			int ans = 0, res;
    			for(int i=2*MAXN-1;i>=0;i--)
    				if( f[i] > ans ) ans = f[i], res = i;
    			string ret = "";
    			while( res ) ret = (char)(res % 10 + '0') + ret, res /= 10;
    			ret = " " + ret;
    			while( ans ) ret = (char)(ans % 10 + '0') + ret, ans /= 10;
    			return ret;
    		}
    };
    

    @details@

    为什么要把函数返回值设置成这么反人类形式,还要把数转化成字符串。直接返回一个数组不挺好的。

  • 相关阅读:
    mysql中delimiter
    error: unpacking of archive failed on file /usr/sbin/zabbix_agent;592e5bc3: cpio: open
    CefSharp中文帮助文档
    ASP.NET Aries 开发框架
    简洁的富文本编辑器
    asp.net core 获取appsettings.json里的配置
    在asp.net core中使用NLog
    临时禁用Resharper
    visual studio 无添加视图 选项
    visual studio(vs)初始化
  • 原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/12466134.html
Copyright © 2011-2022 走看看