我真的不想寫背景
題目描述
某巨魔有一風扇,長得和下圖一個慫樣。
這風扇原來有
任意兩個相鄰的葉片間隔相等,大小質地相同。
這個
風扇一開始還不錯,但是到後來風扇開始報復社會了。
它的葉片從窗戶甩了出去甩到了大街上,砸腫了二胖(二胖以前身材很好,你懂得)。
風扇的葉片脫落是很危險的,因爲這會使風扇失去平衡。
可能當你經過風扇下方時它就直接拿你一血。
但是左圖風扇是平衡的,因爲他的重心在風扇的正中心(至於爲什麼自己想吧)。
現在給你一爛風扇。
需要你判斷它平不平衡,如果不平衡,那麼判斷它最少要拆掉它的多少葉片才能平衡。
輸入格式
第一行兩個數字
接下來
輸出格式
一個數字,表示爲使電風扇平衡所需要拆掉的葉片的最少數量。
樣例輸入
12 5
1
4
5
9
10
樣例輸出
0
樣例解釋
拆完後就是上圖那慫電風扇。
數據範圍
Solution
首先,圖中這個風扇爲什麼平衡成了一大問題,搞出了這個那麼這個題就簡單了(蒟蒻我是想了很久很久很久很久……)
因爲一對對稱的風扇葉肯定是平衡的,如果把它們拿掉也不影響風扇的平衡性。
於是……我就把所有對稱的風扇葉拿掉了。
於是乎變成了下面這個圖:
這是個三等分的風扇,肯定是對稱的。
所以原風扇是平衡的………
所以,我們就要在一個風扇中,找到一個質數
那麼,
列出所有等分的風扇。
風扇序號 | 第一個扇葉 | 第二個扇葉 | 第三個扇葉 | 第四個扇葉 | …… | 最後一個扇葉 |
---|---|---|---|---|---|---|
風扇1 | ||||||
風扇2 | ||||||
風扇3 | ||||||
…… | ||||||
風扇 |
風扇序號 | 第一個扇葉 | 第二個扇葉 | 第三個扇葉 | 第四個扇葉 | …… | 最後一個扇葉 |
---|---|---|---|---|---|---|
風扇1 | ||||||
風扇2 | ||||||
風扇3 | ||||||
…… | ||||||
風扇 |
注意到所有
新建一個源點,向每一個
新建一個匯點,每一個
若某個
要求最少拿去多少個扇葉能使其平衡,等價於拿去若干個等分的風扇,使得剩下來的扇葉最少。
因爲一個扇葉顯然只能放在一個風扇中被拿走,所以問題等價於求我們建的圖的最小割的補集。
求出最大流即可。
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;
}