首先考慮怎樣的集合一定是合法的
發現全部是奇數的集合一定合法,因為每次都是奇數連偶數,偶數連奇數
然后考慮如果集合同時有奇數和偶數是否一定不合法,結論是一定不合法,證明如下:
設某個奇數為 $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; }