CodeForces - 1220D Alex and Julian(思维+数论)
題目鏈接:點擊查看
題目大意:給出一個整數集合B,現在可以根據集合B構造一個無向圖,規定所有的整數(無窮無盡)為頂點,若兩個整數i和j滿足abs(i - j)在集合B中,則 i 和 j 之間可以連一條邊,現在問最少從集合B中刪掉多少個元素,滿足構成的圖為一個二分圖
題目分析:二分圖的定義是不存在奇環,那么在這個題目中什么時候會出現奇環呢?因為頂點的范圍是全部整數,最好想法的就是將奇數和偶數分開來,這樣就是一張完美的二分圖了,既然從奇偶出發,因為是牽扯到abs(i - j)與集合B的關系,所以我們首先需要知道:
如果我們想要將其分為奇偶兩部分的話,顯然必須令集合B中只剩下奇數才行,因為奇數和偶數作差只會出現奇數,因此剛好可以連邊,而后考慮一下奇數和偶數都存在的情況,可以證明一定會存在奇環:
- 假設奇數為x,偶數為y,則點0到點x*y一定有奇環:因為點0可以和點x建邊,因為abs(x-0)=x,點x可以和點2*x建邊,因為abs(2*x-x)=x,以此類推,點0到點x*y之間可以通過x傳遞建立y條邊,點0到點x*y之間可以通過點y傳遞建立x條邊,也就是由點0->點x*y->點0這個環中共有x+y條邊,通過上面的前提我們可以得證,x+y是奇數,故一定存在奇環,證畢
若集合中有奇數有偶數是肯定不符合題意的,那么全部都是偶數的情況呢?因為如果集合中的數全是偶數,我們可以發現,所有的奇數和奇數連成了一個小集合,而所有的偶數和偶數也都連成了一個小集合,也就是說奇數和偶數互不干涉,所以我們需要想辦法將其集合中的數轉換為奇數的情況就能豁然開朗了,這里可以讓集合B中所有的偶數同時除以2,直到出現至少一個奇數為止,這個操作該如何解釋呢?因為現在已經是奇數點在一個集合中,偶數點在一個集合中了,我們可以對其重新編號,也就是讓奇數所在的集合中等量出現奇數和偶數,偶數亦然,此時就相當于將整個集合的編號除以2了,同樣集合B中的元素也需要對應除以2,根據題意保留的元素大概是這樣的:
到此為止,我們發現可以將所有的數按照二的冪次分成不同的集合中去,也就是說在題目給出的集合B中,我們可以選擇任意一個二的冪次的集合進行保留,那么因為題目要求我們刪除掉最少的元素,所以我們選擇最大的那個集合保留即可
代碼:
#include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=2e5+100;LL a[N];int num[N],cnt[100];int get_num(LL x) {int ans=0;while(x%2==0){x>>=1;ans++;}return ans; }int main() { // freopen("input.txt","r",stdin); // ios::sync_with_stdio(false);int n;scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%lld",a+i);num[i]=get_num(a[i]);cnt[num[i]]++;}int mmax=*max_element(cnt,cnt+100);printf("%d\n",n-mmax);for(int i=0;i<100;i++)if(mmax==cnt[i]){for(int j=1;j<=n;j++)if(num[j]!=i)printf("%lld ",a[j]);break;}return 0; }?
總結
以上是生活随笔為你收集整理的CodeForces - 1220D Alex and Julian(思维+数论)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CodeForces - 1220B M
- 下一篇: HDU - 3026 Chinese C