• p4068 [SDOI2016]数字配对


    传送门

    分析

    我们考虑对所有a[i]质因数分解,然后记cnt[i]为a[i]是由几个质数相乘得到的

    然后我们建一个二分图,左面为所有cnt[i]为奇数的点,右面是为偶数的点

    我们从源点向左面点连容量b[i]花费0的边,从右面点向汇点连容量b[i]花费0的边

    然后两排点之间符合条件的点对连容量inf花费c[i]*c[j]的边

    然后跑总花费不小于0的最大费用最大流即可

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<cctype>
    #include<cmath>
    #include<cstdlib>
    #include<queue>
    #include<ctime>
    #include<vector>
    #include<set>
    #include<map>
    #include<stack>
    using namespace std;
    #define int long long
    const int inf = 1e15+7;
    int n,a[500],b[500],C[500],cnt[500];
    int x[500],y[500],l1,l2,s,t,Ans,now,sum; 
    int head[300100],w[300100],c[300100],nxt[300100],to[300100];
    int fm[300100],ano[300100],S;
    inline void add(int x,int y,int z,int cost){
        nxt[++S]=head[x];head[x]=S;to[S]=y;w[S]=z;c[S]=cost;fm[S]=x;
        nxt[++S]=head[y];head[y]=S;to[S]=x;w[S]=0;c[S]=-cost;fm[S]=y;
        ano[S]=S-1;ano[S-1]=S;
    }
    inline int work(int x){
        int i,j,k=0;
        for(i=2;i<=sqrt(x);i++)
          while(x%i==0)x/=i,k++;
        if(x>1)k++;
        return k;
    }
    queue<int>q;
    int iq[100100],nf[100100],la[100100],d[100100];
    inline void go(){
        int i,j,k;
        la[s]=0;
        while(1){
          for(i=1;i<=t;i++)d[i]=-inf;
          q.push(s);
          d[s]=0,nf[s]=inf,iq[s]=1;
          while(!q.empty()){
              int u=q.front();
              q.pop(),iq[u]=0;
              for(i=head[u];i;i=nxt[i])
                if(w[i]&&d[to[i]]<d[u]+c[i]){
                  d[to[i]]=d[u]+c[i];
                  la[to[i]]=i;
                  nf[to[i]]=min(w[i],nf[u]);
                  if(!iq[to[i]]){
                    q.push(to[i]);
                    iq[to[i]]=1;
                  }
                }
          }
          int be=now,ans=Ans,i=la[t];
          if(!nf[t]||d[t]==-inf)return;
          while(i){
              w[i]-=nf[t];
              w[ano[i]]+=nf[t];
              now+=nf[t]*c[i];
              i=la[fm[i]];
          }
          Ans+=nf[t];
          if(now<0){
              Ans=ans+be/abs(d[t]);
              return;
          }
        }
    }
    signed main(){
        int i,j,k;
        scanf("%lld",&n);
        s=n+1,t=n+2;
        for(i=1;i<=n;i++)scanf("%lld",&a[i]),cnt[i]=work(a[i]);
        for(i=1;i<=n;i++)scanf("%lld",&b[i]);
        for(i=1;i<=n;i++)scanf("%lld",&C[i]);
        for(i=1;i<=n;i++)if(cnt[i]&1)
          for(j=1;j<=n;j++)
            if((cnt[i]==cnt[j]+1&&a[i]%a[j]==0)
              ||(cnt[j]==cnt[i]+1&&a[j]%a[i]==0))add(i,j,inf,C[i]*C[j]);
        for(i=1;i<=n;i++)
          if(cnt[i]&1)add(s,i,b[i],0);
            else add(i,t,b[i],0);
        go();
        printf("%lld
    ",Ans);
        return 0;
    }
  • 相关阅读:
    touch:创建文件及修改文件时间戳
    stat:查看文件时间参数
    获取二维数组里面实际存有数据的行数
    Math.Atan2 方法
    c#移位运算符("<<"及">>")
    c# 一维数组和二维数组的几种定义方式<转>
    C#异常处理总结
    C#图片灰度处理(位深度24→位深度8)、C#图片二值化处理(位深度8→位深度1)
    WinForm窗体及其控件的自适应
    C#的WinForm窗体美化
  • 原文地址:https://www.cnblogs.com/yzxverygood/p/10354441.html
Copyright © 2020-2023  润新知