Description
把一个\(n\)片扇叶的电风扇掉了\(k\)片叶子,问至少还要拆掉几片叶子才能使电风扇的重心回到转轴上,求一种满足条件的方案.
HINT
\(n<2\times10^4,n\)有至多2个质因子.
Solution
一个状态的重心在转轴上,当且仅当可以把其拆成若干个相邻扇叶的距离相等的状态.
对于任意一个相邻扇叶的距离相等为\(k\)的状态,可以把其拆成\(x\)个相邻扇叶的距离相等为\(\frac{k}{x}\)的状态\((k|x)\).
所以对\(n\)分解质因数.
如果\(n=1\),不可行.
如果\(n\)只有\(1\)个质因子\(p\),枚举起点,以\(\frac{n}{p}-1\)为间隔,判断每一圈是否完整:不完整,拆掉这圈没掉的;完整,保留.
如果\(n\)只有\(2\)个质因子\(p_1,p_2\),考虑二分图.
判断以\(\frac{n}{p_1}-1\)的每一圈\(i\)是否完整,完整的话\((s,i)=p_1\).
判断以\(\frac{n}{p_2}-1\)的每一圈\(i\)是否完整,完整的话\((i,t)=p_2\).
对有交点于圈的点集\(x,y:(x,y)=+\infty\).
求最小割,没被割去的即为保留的.
判断割去:对于每一条初始容量为\(+\infty\)的边,如果两端点向源/汇的边只有\(1\)条满流,则满流边被割去;如果两端点向源/汇的边都满流,则初始容量大的满流边被割去.
#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 20005
#define M 20000000
#define INF 20005
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
using namespace std;
struct graph{
int nxt,to,f;
}e[M];
int a[N],f[N],tot[N],g[N<<1],dep[N<<1],p[3],n,k,s,t,cnt;
bool b[N],v[N];queue<int> q;
inline int read(){
int ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)){
ret=(ret<<1)+(ret<<3)+c-'0';c=getchar();
}
return ret;
}
inline void addedge(int x,int y,int f){
e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;e[cnt].f=f;
}
inline void adde(int x,int y,int f){
addedge(x,y,f);addedge(y,x,0);
}
inline bool bfs(int u){
memset(dep,0,sizeof(dep));
q.push(u);dep[u]=true;
while(!q.empty()){
u=q.front();q.pop();
for(int i=g[u];i;i=e[i].nxt)
if(e[i].f>0&&!dep[e[i].to]){
q.push(e[i].to);
dep[e[i].to]=dep[u]+1;
}
}
return dep[t];
}
inline int dfs(int u,int f){
if(u==t) return f;
int ret=0;
for(int i=g[u],d;i&&f;i=e[i].nxt)
if(e[i].f>0&&dep[e[i].to]>dep[u]){
d=dfs(e[i].to,min(e[i].f,f));
e[i].f-=d;e[i^1].f+=d;ret+=d;f-=d;
}
if(!ret) dep[u]=-1;
return ret;
}
inline int dinic(){
int ret=0;
while(bfs(s)) ret+=dfs(s,INF);
return ret;
}
inline bool chk(int i,int l){
for(int j=i;j<=n;j+=l)
if(b[j]) return false;
return true;
}
inline void Aireen(){
n=read();k=read();
if(n==1){
puts("-1");return;
}
for(int i=1,j;i<=k;++i){
j=read();b[j]=true;
}
for(int i=2,l=n;i<=n&&l>1;++i){
if(!(l%i)){
while(!(l%i)) l/=i;
p[++cnt]=i;
}
}
if(p[2]){
cnt=1;s=(n<<1)+1;t=s+1;
for(int i=1,l=n/p[1];i<=l;++i)
if(chk(i,l)) adde(s,i,p[1]);
for(int i=1,l=n/p[2];i<=l;++i)
if(chk(i,l)) adde(i+n,t,p[2]);
for(int i=1,l=n/p[1];i<=l;++i)
if(chk(i,l)) for(int j=i;j<=n;j+=l) f[j]=i;
for(int i=1,l=n/p[2];i<=l;++i){
for(int j=i;j<=n;j+=l){
if(!tot[f[j]]&&f[j]&&chk(i,l)) adde(f[j],i+n,INF);
++tot[f[j]];
}
for(int j=i;j<=n;j+=l) --tot[f[j]];
}
dinic();
for(int i=g[s];i;i=e[i].nxt)
if(!(i&1)&&e[i].f){
for(int j=e[i].to,l=n/p[1];j<=n;j+=l)
b[j]=true;
}
else v[e[i].to]=true;
for(int i=g[t];i;i=e[i].nxt)
if((i&1)&&e[i^1].f){
for(int j=e[i].to-n,l=n/p[2];j<=n;j+=l)
b[j]=true;
}
else if((i&1)&&!e[i^1].f){
for(int j=g[e[i].to];j;j=e[j].nxt)
if(v[e[j].to]){
for(int o=e[j].to,l=n/p[1];o<=n;o+=l)
b[o]=true;
}
}
cnt=0;
for(int i=1;i<=n;++i)
if(!b[i]) a[++cnt]=i;
}
else{
cnt=0;
for(int i=1,l=n/p[1];i<=l;++i)
if(!chk(i,l))
for(int j=i;j<=n;j+=l)
if(!b[j]) a[++cnt]=j,b[j]=true;
}
if(cnt==n-k){
printf("-1");return;
}
printf("%d\n",cnt);
for(int i=1;i<=cnt;++i)
printf("%d ",a[i]);
printf("\n");
}
int main(){
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
Aireen();
fclose(stdin);
fclose(stdout);
return 0;
}
2017-03-29 00:04:25