我真的不想寫背景

我真的不想寫背景


題目描述

某巨魔有一風扇,長得和下圖一個慫樣。

這裏寫圖片描述

這風扇原來有 N 個等分葉片,順時針編號 1N (誰是編號 1 這不重要)。
任意兩個相鄰的葉片間隔相等,大小質地相同。
這個 N 滿足 N=PaQbP , Q 爲質數,a , b 爲自然數。
風扇一開始還不錯,但是到後來風扇開始報復社會了。
它的葉片從窗戶甩了出去甩到了大街上,砸腫了二胖(二胖以前身材很好,你懂得)。
風扇的葉片脫落是很危險的,因爲這會使風扇失去平衡。
可能當你經過風扇下方時它就直接拿你一血。
但是左圖風扇是平衡的,因爲他的重心在風扇的正中心(至於爲什麼自己想吧)。
現在給你一爛風扇。
需要你判斷它平不平衡,如果不平衡,那麼判斷它最少要拆掉它的多少葉片才能平衡。


輸入格式

第一行兩個數字 NM ,表示該風扇原來有 N 個葉片現在已經脫落了 M 個葉片。
接下來 M 行,每行一個數字,表示脫落的葉片編號,按升序給出。


輸出格式

一個數字,表示爲使電風扇平衡所需要拆掉的葉片的最少數量。


樣例輸入

12 5
1
4
5
9
10


樣例輸出

0


樣例解釋

拆完後就是上圖那慫電風扇。


數據範圍

30% 的數據:1N10
50% 的數據:1N10000
100% 的數據:1N2106MN


Solution

首先,圖中這個風扇爲什麼平衡成了一大問題,搞出了這個那麼這個題就簡單了(蒟蒻我是想了很久很久很久很久……)
因爲一對對稱的風扇葉肯定是平衡的,如果把它們拿掉也不影響風扇的平衡性。
於是……我就把所有對稱的風扇葉拿掉了。
於是乎變成了下面這個圖:

這裏寫圖片描述

這是個三等分的風扇,肯定是對稱的。
所以原風扇是平衡的………
所以,我們就要在一個風扇中,找到一個質數 k ,使得這 n 個扇葉中,存在一個 k 等分的組合。
那麼,n 肯定是 k 的倍數,而 k 又是質數,所以 k=pq

列出所有等分的風扇。
p 等分的風扇:

風扇序號 第一個扇葉 第二個扇葉 第三個扇葉 第四個扇葉 …… 最後一個扇葉
風扇1 1+np 1+2np 1+3np 1+4np 1+(p1)np
風扇2 2+np 2+2np 2+3np 2+4np 2+(p1)np
風扇3 3+np 3+2np 3+3np 3+4np 3+(p1)np
……
風扇np np+np np+2np np+3np np+4np n

q 等分的扇葉:

風扇序號 第一個扇葉 第二個扇葉 第三個扇葉 第四個扇葉 …… 最後一個扇葉
風扇1 1+nq 1+2nq 1+3nq 1+4nq 1+(q1)nq
風扇2 2+nq 2+2nq 2+3nq 2+4nq 2+(q1)nq
風扇3 3+nq 3+2nq 3+3nq 3+4nq 3+(q1)nq
……
風扇nq nq+nq nq+2nq nq+3nq nq+4nq n

注意到所有 p 等分的風扇互不相交,所有 q 等分的風扇也互不相交。
新建一個源點,向每一個 p 等分的風扇連一條容量爲 p 的邊;
新建一個匯點,每一個 q 等分的風扇向匯點連一條容量爲 q 的邊;

若某個 p 等分的風扇與某個 q 等分的風扇中有一個或幾個扇葉相同,則從這一個 p 等分的風扇連一條容量爲 INF 的邊到這一個 q 等分的風扇。
要求最少拿去多少個扇葉能使其平衡,等價於拿去若干個等分的風扇,使得剩下來的扇葉最少。
因爲一個扇葉顯然只能放在一個風扇中被拿走,所以問題等價於求我們建的圖的最小割的補集。
求出最大流即可。


Code

#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>

#define Min(x,y) ((x)<(y)?(x):(y))

#define s 0
#define t 2000005
#define INF 0x3f3f3f3f

using namespace std;

int n,m,p,q,tot,cnt;

bool w[2000010];
bool vis[2000010];
int in[2000010];

int head[2000010],nxt[8000010],data[8000010],flow[8000010],dis[2000010];
int cur[2000010];
queue<int>qs;

void add(int x,int y,int z){
    nxt[cnt]=head[x];data[cnt]=y;flow[cnt]=z;head[x]=cnt++;
    nxt[cnt]=head[y];data[cnt]=x;flow[cnt]=0;head[y]=cnt++;
}

bool BFS(){
    memset(dis,-1,sizeof dis);
    qs.push(s);dis[s]=0;
    while(!qs.empty()){
        int now=qs.front();
        qs.pop();
        for(int i=head[now];i!=-1;i=nxt[i])if(dis[data[i]]==-1&&flow[i]){
            dis[data[i]]=dis[now]+1;
            qs.push(data[i]);
        }
    }
    return dis[t]!=-1;
}

int dinic(int now,int Flow){
    if(now==t)return Flow;
    int Low;
    for(int &i=cur[now];i!=-1;i=nxt[i])if(dis[data[i]]==dis[now]+1&&flow[i]){
        if(Low=dinic(data[i],Min(Flow,flow[i]))){
            flow[i]-=Low;
            flow[i^1]+=Low;
            return Low;
        }
    }
    return 0;
}

int main(){

    freopen("damn.in","r",stdin);
    freopen("damn.out","w",stdout);

    int maxn=0;

    memset(head,-1,sizeof head);
    scanf("%d%d",&n,&m);int tn=n;
    for(int i=1;i<=m;i++){
        int x;
        scanf("%d",&x);
        w[x]=true;
    }
    bool first=true;
    int sqr=sqrt(n);
    for(int i=2;i<=sqr;i++)
        if(n%i==0&&first){
            first=false;
            p=i;
            while(n%i==0)n/=i;
        }
        else if(n%i==0){
            q=i;
            while(n%i==0)n/=i;
            break;
        }
    if(n!=1)q=n;n=tn;
    for(int i=1;i<=n/p;i++)if(!w[i]){
        for(int j=i;j<=n;j+=n/p)if(w[j])goto nxt;
        ++tot;
        maxn+=p;
        add(s,tot,p);
        for(int j=i;j<=n;j+=n/p){
            in[j]=tot;
        }
        nxt:;
    }
    for(int i=1;i<=n/q;i++)if(!w[i]){
        for(int j=i;j<=n;j+=n/q)if(w[j])goto nxt2;
        ++tot;
        maxn+=q;
        for(int j=i;j<=n;j+=n/q)vis[in[j]]=false;
        for(int j=i;j<=n;j+=n/q){
            if(in[j]&&!vis[in[j]]){
                vis[in[j]]=true;add(in[j],tot,INF);
            }
        }
        add(tot,t,q);
        nxt2:;
    }
    while(BFS()){
        int Low;
        memcpy(cur,head,sizeof head);
        while(Low=dinic(s,INF)){
            maxn-=Low;
        }
    }
    printf("%d\n",n-m-maxn);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章