Codeforces 1220 D. Alex and Julian

在比賽結束後一分鐘過題,前邊的題目浪費了太長的時間

題意

給定一個集合B,讓你從集合中去除最少的元素構造一個二分圖,這個二分圖的點和邊都是無限的,點的編號爲i與編號爲j的節點連接當且僅當ijB|i - j|\in B.

分析與解答

我們考慮通過奇偶性來構造這個二分圖,
如果集合B中全部都爲奇數,我們知道奇數加上一個奇數爲一個偶數,也就是說每條邊都可以溝通一個全部爲奇數的部分和全部爲偶數的部分.
同樣的如果在集合B中既存在奇數又存在偶數,因爲奇數加偶數還爲奇數,偶數加偶數還爲偶數,那麼我們不難發現一定存在矛盾.
如果集合B中全爲偶數(一開始全爲偶數也可以,結果發現想錯了),需要考慮如下情況:
假設集合B爲{2,4}\{2,4\},我們設1在左圖中,那麼3在右圖中,從而5在左圖中,但是根據B中有4我們可以得到5應該在右圖中,出現矛盾.
但是如果集合B爲{2,6}\{2,6\}我們就可以構造成功
於是我們考慮不成立的原因,發現只要在偶數中存在i,ji,j,而且存在a,ba,b奇偶性不同,同時滿足ia=jbi * a = j * b,那麼一定不行.而對於任何一個偶數來說一定是一個奇數與2的多少次方的乘積,如果a,ba,b奇偶性不同,那麼能整除iijj最大二次冪一定不同.
因此對於偶數,我們去枚舉二次冪,找到當前二次冪能表示的所有偶數,即爲當前二次冪下能夠組成二分圖的最大的B的子集(也就是刪除元素最少),找到所有二次冪下最大的那個子集,與奇數集相比較,取較大的那個爲最後剩下的集合,其他爲刪除的元素.

代碼

/*************************************************************************
	> File Name: 2019_10_6_4.cpp
	> Author: z472421519
	> Mail: 
	> Created Time: 2019年10月06日 星期日 16時51分29秒
 ************************************************************************/
 
#include <bits/stdc++.h>
#include <cstdio>
#include <cstring>
#define MAXN 200003
using namespace std;
 
long long a1[MAXN],a2[MAXN],x;
long long cal(int n)
{
    int sum = 0;
    long long sum_id = 2;
    long long now = 2LL;
    //memset(vis,false,sizeof(vis));
    #if 0
    for(int i = 1;i <= n;i++)
    {
 
    }
    #endif
    long long m = 0;
    for(int i = 1;i <= n;i++)
        m = max(a2[i],m);
    while(now <= m)
    {
        int res = 0;
        for(int i = 1;i <= n;i++)
        {
            if(a2[i] % now == 0)
            {
                a2[i] /= now;
                if(a2[i] % 2LL)
                {
                    res++;
                }
                a2[i] *= now;
            }
        }
        //now *= 2LL;
        if(res > sum)
        {
            sum = res;
            sum_id = now;
        }
        now *= 2LL;
    }
    return sum_id;
 
}
int main()
{
    int n;
    scanf("%d",&n);
    int sum1 = 0,sum2 = 0;
    for(int i = 1;i <= n;i++)
    {
        scanf("%I64d",&x);
        if(x % 2LL == 0)
        {
            a2[++sum2] = x;
        }
        else
        {
            a1[++sum1] = x;
        }
    }
    long long now = cal(sum2);
    //printf("%lld\n",now);
    //for(int i = 1;i <= )
    int res = 0;
    for(int i = 1;i <= sum2;i++)
        {
            if(a2[i] % now == 0)
            {
                a2[i] /= now;
                if(a2[i] % 2LL)
                {
                    res++;
                }
                a2[i] *= now;
            }
        }
    if(res > sum1)
    {
        printf("%d\n",n - res);
        for(int i = 1;i <= sum1;i++)
            if(a1[i] % now)
                printf("%I64d ",a1[i]);
        for(int i = 1;i <= sum2;i++)
            if(a2[i] % now || (a2[i] % now == 0 && (a2[i] / now) % 2LL == 0))
                printf("%I64d ",a2[i]);
    }
    else
    {
        printf("%d\n",sum2);
        for(int i = 1;i <= sum2;i++)
                printf("%I64d ",a2[i]);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章