HNOI2017模拟赛 C题
作者:互联网
题目:
分析:
开始觉得是神仙题。。。
然后发现n最多有2个质因子
这说明sm呢。。。
学过物理的小朋友们知道,当一个物体受多个不同方向相同的力时,只有相邻力的夹角相等,受力就会平衡
于是拆扇叶相当于在风扇上等分角度
考虑贪心的话,就是一次拆越少,也就是角度分越大越好
那就要用到质因子了
先将编号改为(0~n-1)
首先一个质因子p的情况很好处理,当一个扇叶x掉下时,必须拆下y(其中y mod n/p = x mod n/p)的扇叶
于是直接打标记就好了
然后就是2个质因子的情况
那么一个风扇叶如果要下来,那么它所对应的拆卸方式就有两种
而且这两种只能选一种
同类质因数的情况还不会影响。。。
令掉下来的点所对应的两种方案连边
然后会形成一个二分图
每一种方案对应一个代价
然后代价最少。。。
唔。。。
最小割了
写一会调一会中途还差点认为自己想错了
搞了好久。。
代码实现能力太差了。。
#include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<algorithm> #define maxn 40005 #define maxm 300005 #define INF 0x3f3f3f3f using namespace std; inline int getint() { int num=0,flag=1;char c; while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1; while(c>='0'&&c<='9')num=num*10+c-48,c=getchar(); return num*flag; } int n,K,S,T; int fir[maxn],nxt[maxm],to[maxm],cap[maxm],cnt; int h[maxn],tp[maxn]; int pri[maxn],np[maxn],cur; int A,B; int num[maxn],ans[maxn],vis[maxn],pos[maxn]; inline void newnode(int u,int v,int w) {to[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt,cap[cnt]=w;} inline void insert(int u,int v,int w) {newnode(u,v,w),newnode(v,u,0);} inline bool bfs() { memset(h,-1,sizeof h); queue<int>Q;h[S]=0,Q.push(S); while(!Q.empty()) { int u=Q.front();Q.pop(); for(int i=fir[u];i;i=nxt[i]) if(cap[i]&&!~h[to[i]]) { h[to[i]]=h[u]+1,Q.push(to[i]); if(to[i]==T)return 1; } } return 0; } inline int aug(int u,int flow) { if(u==T)return flow; int used=0; for(int i=tp[u];i;i=nxt[i]) { tp[u]=i; if(cap[i]&&h[to[i]]==h[u]+1) { int w=flow-used; w=aug(to[i],min(cap[i],w)); cap[i]-=w,cap[i^1]+=w,used+=w; if(used==flow)return flow; } } if(!used)h[u]=-1; return used; } inline int dinic() { int num=0; while(bfs())memcpy(tp,fir,sizeof fir),num+=aug(S,INF); return num; } inline void init() { np[1]=1; for(int i=2;i<=n;i++) { if(!np[i])pri[++cur]=i; for(int j=1;j<=cur&&i*pri[j]<=n;j++) { np[i*pri[j]]=1; if(i%pri[j]==0)break; } } } inline void dfs(int u) { vis[u]=1; for(int i=fir[u];i;i=nxt[i])if(cap[i]&&!vis[to[i]])dfs(to[i]); } int main() { n=getint(),K=getint(); init(); for(A=1;A<=cur;A++)if(n%pri[A]==0)break; for(B=A+1;B<=cur;B++)if(n%pri[B]==0)break; if(n==1){printf("-1\n");return 0;} if(B>cur) { A=n/pri[A]; for(int i=1;i<=K;i++) { int x=getint();ans[x]=1; if(!vis[x])for(int j=(x-1)%A+1;j<=n;j+=A)vis[j]=1; } int num=0; for(int i=1;i<=n;i++)num+=vis[i]; if(num==n){printf("-1\n");return 0;} printf("%d\n",num-K); for(int i=1,flag=0;i<=n;i++) if(vis[i]&&!ans[i]) { printf("%d",i); if((++flag)==num-K)printf("\n"); else printf(" "); } } else { A=n/pri[A],B=n/pri[B]; S=A+B+1,T=S+1,cnt=1; for(int i=1;i<=A;i++)num[i]=n/A; for(int i=1;i<=B;i++)num[A+i]=n/B; for(int i=1;i<=K;i++) { int x=getint();ans[x]=1; int tmp1=(x-1)%A+1,tmp2=(x-1)%B+A+1; pos[tmp1]=pos[tmp2]=1; num[tmp1]--,num[tmp2]--; } for(int i=1;i<=n;i++) { int tmp1=(i-1)%A+1,tmp2=(i-1)%B+A+1; if(pos[tmp1]&&pos[tmp2])insert(tmp1,tmp2,INF); } for(int i=1;i<=A;i++)if(pos[i])insert(S,i,num[i]); for(int i=A+1;i<=A+B;i++)if(pos[i])insert(i,T,num[i]); int sum=dinic(); if(sum==n-K){printf("-1\n");return 0;} printf("%d\n",sum); dfs(S); for(int i=1;i<=A;i++)if(pos[i]&&!vis[i])for(int j=i;j<=n;j+=A)ans[j]^=1; for(int i=1;i<=B;i++)if(pos[i+A]&&vis[i+A])for(int j=i;j<=n;j+=B)ans[j]^=1; for(int i=1,flag=0;i<=n;i++) if(ans[i]) { printf("%d",i); if((++flag)==sum){printf("\n");break;} else printf(" "); } } }View Code
标签:used,return,int,cap,flow,HNOI2017,include,模拟 来源: https://www.cnblogs.com/Darknesses/p/12025069.html