【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;
}

原文地址:https://www.cnblogs.com/AWCXV/p/8404347.html

时间: 2024-11-09 13:04:06

【Henu ACM Round#20 D】 Devu and Partitioning of the Array的相关文章

【Henu ACM Round#15 F】Arthur and Questions

[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] a1+a2+...+aka1<ak+1 a2+a3+...+ak+1a2<ak+2 类似还可以推出 a3<ak+3 a4<ak+4 ... 则有 a1<ak+1<a2k+1<a3k+1... a2<ak+2<a2k+2<a3k+2... ... 也就是每隔k个要是递增的. 你的任务就是维护每隔k个数字递增. 我们先考虑a[1],a[1+k],a[1+2k],a[1+3k]...这

【Henu ACM Round #13 C】 Ebony and Ivory

[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 先求出c-bx的所有可能 ->存在map里面 然后枚举y看看ay在不在map里面 在的话就有解. 这样复杂度是\(O(N*log_2N)\)的 比直接两层循环枚举的\(O(N^2)\)复杂度要来的好 这种方法也叫"中途相遇法" [代码] #include <bits/stdc++.h> #define ll long long using namespace std; ll a,b,c; map<

【Henu ACM Round #13 B】Spider Man

[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 会发现每个环可以操作的次数是固定的. (环的大小-1 也就是说一旦环确定了.其实结果就已经确定了. 则直接看操作总数的奇偶性就可以了. [代码] #include <bits/stdc++.h> #define long long using namespace std; int n,x; int main(){ #ifdef LOCAL_DEFINE freopen("rush_in.txt", &quo

【Henu ACM Round #13 D】A Trivial Problem

[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 123...n中末尾0的个数 只会由素因子2和5的个数决定且等于 Min{cnt[2],cnt[5]} 且素因子2的个数一定会比5多; 所以n!的末尾0的个数 等于for (int i = 1;i <= n;i++)中所有i的5因子的个数和 枚举一下就好 [代码] #include <bits/stdc++.h> using namespace std; const int N = 1e7; int n; vector&

【Henu ACM Round #13 E】Spy Syndrome 2

[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 对m个串建立一棵字典树. 然后对主串. 尝试从第一个位置开始.在字典树中尝试匹配 如果匹配到了位置i 就再从位置i+1开始尝试匹配 (这时又重新从根节点开始重新匹配 每次匹配最多只要往下走50步. 写个递归的过程就好. [代码] #include <bits/stdc++.h> using namespace std; const int N = 1e6; const int NN = 1e4; const int M = 1

【Henu ACM Round#14 A】Vitaly and Night

[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 连续两个如果不全是0就递增cnt [代码] #include <bits/stdc++.h> using namespace std; int n,m; int main() { cin >> n >>m; int cnt = 0; for (int i = 1;i <= n;i++){ int x,y; for (int j = 1;j <= m;j++){ cin >>x &

【Henu ACM Round#14 C】Duff and Weight Lifting

[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 2^y可以由两个2^(y-1)相加得到. 则有一个贪心的策略. 就是2^x尽量都变成2^(x+1) (即能够凑就尽量凑) 如果x还有剩余的话.答案递增1 而凑上去的数字,显然是可以合并成1步操作的.因为他们的和就是2^(x+1) [代码] #include <bits/stdc++.h> #define ll long long using namespace std; const int N = 1e6; int n,a[N

【Henu ACM Round#15 E】 A and B and Lecture Rooms

[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 最近公共祖先. (树上倍增 一开始统计出每个子树的节点个数_size[i] 如果x和y相同. 那么直接输出n. 否则求出x和y的最近公共祖先.z (假定y的深度大于x [1]如果z等于x或y中的一个. 那么久就找到x..y的路径(长度设为L)中的中点u. 显然,u和它的其他len-1个子树上的任意一个节点都是可行的(除了那个包含y的子树 设_get(x,step)表示x节点往上走step步到达的节点 则输出_sum[中点]-_s

【Henu ACM Round#15 A】 A and B and Chess

[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 统计大写和小写的个数. 比较答案.输出即可. [代码] #include <bits/stdc++.h> using namespace std; string s[10]; map<char,int> dic; int inc[300]; int main() { for (int i = 0;i < 8;i++) cin >> s[i]; for (int i = 0;i < 8;i++