我真的不想写背景
题目描述
某巨魔有一风扇,长得和下图一个怂样。
这风扇原来有
N
个等分叶片,顺时针编号
任意两个相邻的叶片间隔相等,大小质地相同。
这个
N
满足
风扇一开始还不错,但是到后来风扇开始报复社会了。
它的叶片从窗户甩了出去甩到了大街上,砸肿了二胖(二胖以前身材很好,你懂得)。
风扇的叶片脱落是很危险的,因为这会使风扇失去平衡。
可能当你经过风扇下方时它就直接拿你一血。
但是左图风扇是平衡的,因为他的重心在风扇的正中心(至于为什么自己想吧)。
现在给你一烂风扇。
需要你判断它平不平衡,如果不平衡,那么判断它最少要拆掉它的多少叶片才能平衡。
输入格式
第一行两个数字
N
,
接下来
M
行,每行一个数字,表示脱落的叶片编号,按升序给出。
输出格式
一个数字,表示为使电风扇平衡所需要拆掉的叶片的最少数量。
样例输入
12 5
1
4
5
9
10
样例输出
0
样例解释
拆完后就是上图那怂电风扇。
数据范围
50%
的数据:
1≤N≤10000
。
100%
的数据:
1≤N≤2∗106
,
M≤N
。
Solution
首先,图中这个风扇为什么平衡成了一大问题,搞出了这个那么这个题就简单了(蒟蒻我是想了很久很久很久很久……)
因为一对对称的风扇叶肯定是平衡的,如果把它们拿掉也不影响风扇的平衡性。
于是……我就把所有对称的风扇叶拿掉了。
于是乎变成了下面这个图:
这是个三等分的风扇,肯定是对称的。
所以原风扇是平衡的………
所以,我们就要在一个风扇中,找到一个质数
k
,使得这
那么,
列出所有等分的风扇。
风扇序号 | 第一个扇叶 | 第二个扇叶 | 第三个扇叶 | 第四个扇叶 | …… | 最后一个扇叶 |
---|---|---|---|---|---|---|
风扇1 | 1+np | 1+2np | 1+3np | 1+4np | 1+(p−1)np | |
风扇2 | 2+np | 2+2np | 2+3np | 2+4np | 2+(p−1)np | |
风扇3 | 3+np | 3+2np | 3+3np | 3+4np | 3+(p−1)np | |
…… | ||||||
风扇 np | np+np | np+2np | np+3np | np+4np | n |
风扇序号 | 第一个扇叶 | 第二个扇叶 | 第三个扇叶 | 第四个扇叶 | …… | 最后一个扇叶 |
---|---|---|---|---|---|---|
风扇1 | 1+nq | 1+2nq | 1+3nq | 1+4nq | 1+(q−1)nq | |
风扇2 | 2+nq | 2+2nq | 2+3nq | 2+4nq | 2+(q−1)nq | |
风扇3 | 3+nq | 3+2nq | 3+3nq | 3+4nq | 3+(q−1)nq | |
…… | ||||||
风扇 nq | nq+nq | nq+2nq | nq+3nq | nq+4nq | n |
注意到所有
新建一个源点,向每一个
新建一个汇点,每一个
若某个
要求最少拿去多少个扇叶能使其平衡,等价于拿去若干个等分的风扇,使得剩下来的扇叶最少。
因为一个扇叶显然只能放在一个风扇中被拿走,所以问题等价于求我们建的图的最小割的补集。
求出最大流即可。
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;
}