• 旗鼓相当的对手


    前言

    构造题?还是 MO 二试改的?那没事了。

    题目

    题目大意:

    酒馆又来了一批新客人,为了招待他们,鲍勃决定安排一场精彩的战斗!

    鲍勃从 (m) 个随从里挑选了 (n) 个随从 (a_i),秉着一切从简的原则,这 (m) 个随从的战斗力为 ([1,m]) 之间的整数。

    为了战斗更具观赏性,参加战斗的随从不能太少,所以 (lfloorfrac{2m}{3} floor<nle m)

    鲍勃认为最精彩的战斗是匹配两个旗鼓相当的对手!但是这时他却犯了难,因为这里不止两个人,他不知道怎么分队!于是这个任务就交给了在旁边打工的你,你需要将这 (n) 个随从分成 (2) 组,每组战斗力之和相同。

    无解需要报告Chaotic evil,否则先输出NP-Hard solved,再用 (-1)(1) 表示分组。

    (3le nle m le 10^6.) 保证鲍勃挑选的随从战斗力之和为偶数。

    讲解

    讲个笑话,从大到小暴力贪心 dfs 有 88pts。

    构造题显然没有什么思路可言,所以我们直接讲构造方法。

    首先把 (n) 当做偶数,奇数的话补个 (0)

    然后排序,令 (d_i=a_{2i}-a_{2i-1}),可以发现 (sum d_ile m-frac{n}{2}<n),且 (sum d_i) 是偶数。

    我们来试图调整 (d_i) 的正负以达到我们的目标,我们令 (N=frac{n}{2}),限制可以表现为 (sum d_i<2N)

    考虑归纳构造:

    • (N=1) 时显然成立,因为 (sum d_i<2N)(sum d_i) 为偶数。
    • (N>1) 时,若 (d_i=1) ,显然有解。否则我们挑出最大的 (d_{max}) 和最小的 (d_{min}),删掉他们并加入 (d_{max}-d_{min}),不难发现 (sum d_i) 至少减少 (2)(sum d_i) 依然是偶数,(N'=N-1),成功归纳到子问题。

    官方题解到这里就结束了,怎么实现呢?

    这里给出两个思路:

    1. 我们直接模拟这个过程,考虑怎么打符号反转的标记,可以采用 set+启发式合并的做法,时间复杂度 (O(nlog_2^2n)),如果用可并堆可以做到 (O(nlog_2n)),没试过,理论能过。
    2. 抛开我的 rubbish 做法,来看卷爷的做法,我们直接并查集开 (2N) 个点,(i)(i+N) 表示符号,每次做也只需连边表示数与数之间正负号的异同,找最大最小可以用 set,时间复杂度 (O(nlog_2n)),常数更小,而且我下面的代码也是这个做法。

    代码

    小常数

    //12252024832524
    #include <bits/stdc++.h>
    #define TT template<typename T>
    using namespace std;
    
    typedef long long LL;
    const int MAXN = 1000005;
    int n,m,sg;
    int a[MAXN],od[MAXN],f[MAXN];
    bool ans[MAXN];
    
    LL Read()
    {
    	LL x = 0,f = 1; char c = getchar();
    	while(c > '9' || c < '0'){if(c == '-') f = -1;c = getchar();}
    	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
    	return x * f;
    }
    TT void Put1(T x)
    {
    	if(x > 9) Put1(x/10);
    	putchar(x%10^48);
    }
    TT void Put(T x,char c = -1)
    {
    	if(x < 0) putchar('-'),x = -x;
    	Put1(x); if(c >= 0) putchar(c);
    }
    TT T Max(T x,T y){return x > y ? x : y;}
    TT T Min(T x,T y){return x < y ? x : y;}
    TT T Abs(T x){return x < 0 ? -x : x;}
    
    int findSet(int x)
    {
    	if(f[x]^x) f[x] = findSet(f[x]);
    	return f[x];
    }
    void unionSet(int u,int v){f[findSet(u)] = findSet(v);}
    struct node
    {
    	int val,ID;
    	bool operator < (const node &px)const{
    		if(val^px.val) return val < px.val;
    		return ID < px.ID; 
    	}
    };
    set<node> s;
    
    int main()
    {
    //	freopen("chaoticevil.in","r",stdin);
    //	freopen("chaoticevil.out","w",stdout);
    	n = Read(); m = Read();
    	for(int i = 1;i <= n;++ i) a[i] = Read();
    	if(n&1) ++n,sg = 1;
    	for(int i = 1;i <= n;++ i) f[i] = i,od[i] = i;
    	sort(od+1,od+n+1,[](int x,int y){
    		return a[x] < a[y];
    	});
    	n >>= 1;
    	for(int i = 1;i <= n;++ i) s.insert(node{a[od[i<<1]]-a[od[(i<<1)-1]],i});
    	while(s.size() > 1)
    	{
    		auto it1 = s.begin(),it2 = s.end(); --it2;
    		unionSet(it1->ID,it2->ID+n);
    		unionSet(it1->ID+n,it2->ID);
    		node ne = node{it2->val-it1->val,it2->ID};
    		s.erase(it2); s.erase(s.begin());
    		s.insert(ne);
    	}
    	for(int i = 1;i <= n;++ i)
    		if(findSet(i)^findSet(1)) ans[od[i<<1]] = 1;
    		else ans[od[(i<<1)-1]] = 1;
    	n <<= 1;
    	printf("NP-Hard solved
    ");
    	for(int i = 1;i <= n - sg;++ i)
    	{
    		if(ans[i]) Put(1);
    		else Put(-1);
    		putchar(i == (n-sg) ? '
    ' : ' ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    PBI REFRESH ERROR
    PTE
    Python
    Chromedriver下载地址
    python pip安装selenium时报错, ..has requirement websocket-client==0.48.0, but you'll have websocket -client 0.57.0 which is incoopatibale.
    在打开方式里只有wps,找不到默认的MS OFFICE办公PPT打开方式 解决方案
    POWER BI
    POWER BI
    [未解决]POWER BI
    POWER BI 生成日期表
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/15515265.html
Copyright © 2020-2023  润新知