Henu ACM Round#20 D Devu and Partitioning of the Array

Posted Visitor

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Henu ACM Round#20 D Devu and Partitioning of the Array相关的知识,希望对你有一定的参考价值。

【链接】 我是链接,点我呀:)
【题意】


在这里输入题意

【题解】


一开始所有的数字单独成一个集合。
然后用v[0]和v[1]记录集合的和偶数奇数的集合它们的根节点(并查集

然后先让v[0]的大小变成p

//奇数+偶数是奇数
//奇数+奇数是偶数
//偶数+偶数是偶数

如果v[0].size < p
那么随便让两个和为奇数的集合,让他们合并在一起,加入到偶数集合中,那么v[0].size++,v[1].size-=2了

如果v[0].size > p
那么有两种方法
?1.让两个偶数集合合并在一起,变成一个更大的偶数集合,v[0].size()--
?2.让一个偶数集合和一个奇数集合合并在一起,变成一个奇数集合,v[0].size()--,但是奇数集合个数还是不变

此后v[0].size==p了

那么接下来只要调整v[1].size就好了
但是在调整之前先判断v[0].size()+v[1].size()>=k是否成立

如果小于k的话,是肯定没办法变多的。
因为越并只能越少的

然后如果大于k的话,只能把v[1]的大小变小了。
根据上面奇数和偶数相加的规则。
不难发现。
只能把两个奇数合并成偶数才能减少奇数的个数。
且显然奇数只能两个两个地减少。
减少的过程如下
1.把两个奇数合并成1个偶数。
2.把新合成的那个偶数去掉
?有两种去掉的方法
?? ①用两个偶数集合合成一个新的偶数集合
?? ②再用一个奇数和这个偶数,合成一个奇数集合

最后看看v[0].size()+v[1].size()是否等于k就好。
最后根据并查集的根节点。
输出每个集合里面的元素就好。

【代码】

#include <bits/stdc++.h>
using namespace std;



//????????????ж??????????ж????
//????+?????????
//????+?????????
//???+????????
//?????????p?????
//?????е??
// ????????????????

const int N = 1e5;

int n,k,p;
int f[N+10],a[N+10];
vector<int> v[2];
vector<int> bo[N+10];

int ff(int x){
    if (f[x]==x)
        return x;
    else
        return f[x] = ff(f[x]);
}

int qu(int idx){
    int x = v[idx].back();
    v[idx].pop_back();
    return x;
}

int main()
{
    ios::sync_with_stdio(0),cin.tie(0);
    cin >> n >> k >> p;

    for (int i = 1;i <= n;i++){
        cin >> a[i];
        v[a[i]%2].push_back(i);
    }
    for (int i = 1;i <= n;i++) f[i] = i;


    while ((int)v[0].size()<p){
        if ((int)v[1].size()>=2){
            int x = qu(1),y = qu(1);
            int r1 = ff(x),r2 = ff(y);
            f[r1] = r2;
            v[0].push_back(r2);
        }else{
            return cout<<"NO"<<endl,0;
        }
    }
    //a[0] >= p
    while ((int)v[0].size()>p){
        if ((int)v[0].size()>1){
            int x = qu(0),y = qu(0);
            int r1 = ff(x),r2 = ff(y);
            f[r1] = r2;
            v[0].push_back(r2);
            continue;
        }
        if ((int)v[1].size()>0){
            int x = qu(1);
            int y = qu(0);
            int r1 = ff(x),r2 = ff(y);
            f[r1]=r2;
            v[1].push_back(r2);
        }else return cout<<"NO"<<endl,0;
    }

    //a[0]==p
    if ((int)v[0].size()+(int)v[1].size()<k){
        return cout<<"NO"<<endl,0;
    }

//????+?????????
//????+?????????
//???+????????
    while ((int)v[0].size()+(int)v[1].size()>k){
        if ((int)v[1].size()>=2){
            int x = qu(1),y = qu(1);
            int r1 = ff(x),r2 = ff(y);
            f[r1] = r2;
            v[0].push_back(r2);
        }else{
            return cout<<"NO"<<endl,0;
        }
        if ((int)v[0].size()>1){
            int x = qu(0),y = qu(0);
            int r1 = ff(x),r2 = ff(y);
            f[r1] = r2;

            v[0].push_back(r2);
        }else if ((int)v[0].size()>0 && (int)v[1].size()>0){
            int x = qu(0),y = qu(1);
            int r1 = ff(x),r2 = ff(y);
            f[r1] = r2;
            v[1].push_back(r2);
        }else return cout<<"NO"<<endl,0;
    }

    if ((int)v[0].size()+(int)v[1].size()<k){
        cout<<"NO"<<endl;
        return 0;
    }

    cout<<"YES"<<endl;
    for (int i = 1;i <= n;i++){
        int r = ff(i);
        bo[r].push_back(i);
    }

    for (int i = 1;i <= n;i++)
        if (!bo[i].empty()){
            cout<<(int)bo[i].size()<<' ';
            for (int x:bo[i]){
                cout<<a[x]<<' ';
            }
            cout<<endl;
        }
    //a[0]==p
    return 0;
}

以上是关于Henu ACM Round#20 D Devu and Partitioning of the Array的主要内容,如果未能解决你的问题,请参考以下文章

???Henu ACM Round#15 D???Ilya and Escalator

Henu ACM Round#19 D Points on Line

Henu ACM Round#20 F Arthur and Brackets

Henu ACM Round#24 Ak-String

Henu ACM Round #13 BSpider Man

???Henu ACM Round#17 B???USB Flash Drives