20191211 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

posted @ 2019-12-11 20:54  Izayoi_Doyo  阅读(294)  评论(0编辑  收藏  举报