Codeforces 1220D. Alex and Julian


傳送門

首先考慮怎樣的集合一定是合法的

發現全部是奇數的集合一定合法,因為每次都是奇數連偶數,偶數連奇數

然后考慮如果集合同時有奇數和偶數是否一定不合法,結論是一定不合法,證明如下:

設某個奇數為 $2x+1$ ,某個偶數為 $2y$,那么 $0$ 到 $(2x+1)*(2y)$ 就有兩種路線,$2x+1$ 步和 $2y$ 步的,

這兩條路線剛好構成一個奇環,所以一定不是二分圖

所以一種合法方案就是全留奇數,但是還不夠,因為可能刪掉一些奇數和偶數以后只剩下偶數也是合法的,比如 $2,6$ 就是合法的

發現如果只剩下偶數,那么我們可以把所有偶數同時除以 $2$,這樣並不影響集合的性質,證明的話可以這樣考慮:

所有數都是偶數的情況下,編號為偶數的點只會連向編號為偶數的點,奇數點也只能連奇數點,那么我們可以把這兩種點分開來

然后重新按原編號大小編號為 $0,1,...$,其實就是偶數點的編號全部除以 $2$,奇數點的編號全部 $-1$ 再除以 $2$

發現這樣新的兩個圖其實是一樣的並且就是原集合的數都除以 $2$ 以后構成的圖,所以證明完畢

然后除以二以后發現又有些奇數有些偶數了,繼續遞歸地考慮即可

所以,可能的方案應該是這樣的:

1. 全留奇數
2. 把1.奇數都扔了,然后全留/2后是奇數的數
3. 把1.2.的奇數都扔了,全留/4后是奇數的數
...

然后直接模擬即可,復雜度 $O(n \log 10^{18})$

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
inline ll read()
{
    ll x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int N=2e5+7;
ll n,a[100][N],ans=-1,p;
int main()
{
    n=read();
    for(int i=1;i<=n;i++) a[0][i]=read();
    for(int i=0;i<100;i++)
    {
        ll res=0; bool flag=0;
        for(int j=1;j<=n;j++)
        {
            if(a[i][j]&1) res++;
            if(a[i][j]) flag=1;
        }
        if(!flag) break;
        if(res>ans) ans=res,p=i;
        for(int j=1;j<=n;j++)
        {
            if(a[i][j]&1) a[i+1][j]=0;
            else a[i+1][j]=a[i][j]>>1;
        }
    }
    printf("%lld\n",n-ans);
    for(int i=1;i<=n;i++)
        if((a[p][i]&1)==0) printf("%lld ",a[0][i]);
    if(n-ans) puts("");
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM