• 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
    ");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
    ");return 0;}
            printf("%d
    ",num-K);
            for(int i=1,flag=0;i<=n;i++)
                if(vis[i]&&!ans[i])
                {
                    printf("%d",i);
                    if((++flag)==num-K)printf("
    ");
                    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
    ");return 0;}
            printf("%d
    ",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("
    ");break;}
                    else printf(" ");
                }
        }
    }
    View Code

  • 相关阅读:
    建站两个月,说说我的想法
    我见过的郭弃疾先生(兰亭集势CEO)
    C#数组和集合互相转换的几种方法的效率分析
    (五)React Ant Design Pro + .Net5 WebApi:后端环境搭建Autofac注入+ 泛型仓储
    关于C++中对私有的测试总结
    uint8_t / uint16_t / uint32_t /uint64_t 是什么数据类型(转)
    GDB调试
    linux删除乱码文件
    转:C++ nan
    vim
  • 原文地址:https://www.cnblogs.com/Darknesses/p/12025069.html
Copyright © 2020-2023  润新知