1 条题解

  • 0
    @ 2025-8-24 21:50:00

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Alex_Wei
    **

    搬运于2025-08-24 21:50:00,当前版本为作者最后更新于2021-12-19 22:32:18,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    *P3540 [POI2012]SQU-Squarks

    POI 合集

    将给出的 sis_i 和要求的 xix_i 都从大到小排序,s1=x1+x2s_1=x_1+x_2s2=x1+x3s_2=x_1+x_3,这一点显然。

    先考虑已知一些数时,如何推出剩下来的数:假设 x1xrx_1\sim x_r 已知,它们两两相加可以形成一些和 tjt_j,用可重集 ss 减去可重集 tt,我们能得到一个最大数 sps_p,它只能是 x1+xr+1x_1+x_{r+1} 的和,否则与 sps_p 的最大性违背。

    因此,我们断言如果确定 x1x_1,那么可以在 O(n2logn)\mathcal{O}(n^2\log n) 的时间内得到整个 xix_i:找到可重集 s\ts\backslash ttt 的定义如上)中最大的数 sps_p,反推出 xr+1x_{r+1},用 xr+1x_{r+1}x1xrx_1\sim x_r 的和更新 tt,再找到下一个最大的 sps\ts_{p'}\in s\backslash t' 反推出 xr+2x_{r+2},以此类推。根据 sps_p 的单调性可以用指针维护 pplog\log 由用 xr+1+xix_{r+1}+x_i 通过 map 打标记产生(代码用了 priority_queue)。特别的,若求出的 xr+1xrx_{r+1}\geq x_rxr+10x_{r+1}\leq 0tSt\nsubseteq S钦定的 x1x_1 无解

    接下来考虑如何求 x1x_1:注意到 x2+x3x_2+x_3 仅有可能小于 x1+xi (2in)x_1+x_i\ (2\leq i\leq n),因此 x2+x3x_2+x_3 在从大到小排过序后的 ss 中下标不会超过 nn。考虑直接枚举这个下标从而解出 x1,x2x_1,x_2x3x_3

    综上,时间复杂度三方对数。由于大部分下标很快无解,因此常数非常小。

    const int N = 300 + 5;
    int n, m, a[N * N >> 1];
    uint mp[N * N * 35];
    void s(int x) {mp[x >> 5] |= 1u << (x & 31);}
    bool query(int x) {return mp[x >> 5] >> (x & 31) & 1;}
    vector <vint> ans;
    
    int main(){
    	cin >> n, m = n * (n - 1) >> 1;
    	for(int i = 1; i <= m; i++) a[i] = read(), s(a[i]);
    	sort(a + 1, a + m + 1), reverse(a + 1, a + m + 1);
    	for(int i = 3; i <= n; i++) if(i == 3 || a[i] != a[i - 1]) {
    		static int x[N], sum; sum = a[1] + a[2] + a[i];
    		if(sum & 1) continue; x[1] = (sum >> 1) - a[i];
    		if(x[1] < n) continue;
    		priority_queue <int> q; bool ok = 1;
    		for(int j = 2, p = 1; j <= n && ok; j++) {
    			while(!q.empty() && q.top() == a[p]) q.pop(), p++;
    			x[j] = a[p] - x[1];
    			if(x[j] >= x[j - 1] || x[j] < 0) ok = 0;
    			for(int k = 1; k < j && ok; k++) ok &= query(x[k] + x[j]), q.push(x[k] + x[j]); 
    		} if(ok) {vint p; for(int j = n; j; j--) p.pb(x[j]); ans.pb(p);}
    	}
    	cout << ans.size() << endl, rev(ans);
    	for(vint it : ans) {for(int p : it) cout << p << " "; cout << endl;}
    	return flush(), 0;
    }
    
    • 1

    信息

    ID
    2616
    时间
    1000ms
    内存
    512MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者