zoukankan      html  css  js  c++  java
  • 【JSOI2009】球队收益

    题面

    https://www.luogu.org/problem/P4307

    题解

    日膜一发$aysn$。

    点数为$2n+m$的二分图做法很容易能想到。

    把每个人拆成成功点和失败点,然后一个人胜的场数就是所有和他比赛的人的失败场数之和,在新建点限制流量就行了。

    更优做法,点数$n+m$:

    调整法。

    先假设每个人都输了,然后一场比赛中,赢的人就是胜场+1,败场-1,输的不变。

    这样貌似把一个二元函数变成一元函数了。

    然后算边权,直接按上面一个方法连边就行了,不用拆点了。

    #include<queue>
    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define N 10050
    #define INF 1000000007
    #define S 0
    #define T (n+m+1)
    #define LL long long
    #define ri register int
    using namespace std;
    
    int n,m;
    int a[N],b[N],preb[N],c[N],d[N],e[N];
    int u[N],v[N];
    
    struct graph {
      vector<int> to,w,c;
      vector<int> ed[N];
      LL dis[N]; int cur[N];
      bool vis[N];
      void add_edge(int a,int b,int aw,int ac) {
        to.push_back(b); w.push_back(aw); c.push_back(ac);  ed[a].push_back(to.size()-1);
        to.push_back(a); w.push_back(0);  c.push_back(-ac); ed[b].push_back(to.size()-1);
      }
      bool spfa() {
        memset(dis,0x3f,sizeof(dis));
        memset(vis,0,sizeof(vis));
        queue<int> q;
        dis[S]=0;q.push(S);vis[S]=1;
        while (!q.empty()) {
          int x=q.front(); q.pop();
          for (ri i=0;i<ed[x].size();i++) {
            int e=ed[x][i];
            if (dis[to[e]]>dis[x]+c[e] && w[e]) {
              dis[to[e]]=dis[x]+c[e];
              if (!vis[to[e]]) vis[to[e]]=1,q.push(to[e]);
            }
          }
          vis[x]=0;
        }
        return dis[T]<INF;
      }
      int dfs(int x,int lim) {
        if (x==T || !lim) return lim;
        LL sum=0; vis[x]=1;
        for (ri &i=cur[x];i<ed[x].size();i++) {
          int e=ed[x][i];
          if (dis[x]+c[e]==dis[to[e]] && w[e] && !vis[to[e]]) {
            int f=dfs(to[e],min(lim,w[e]));
            w[e]-=f; w[1^e]+=f;
            lim-=f; sum+=f;
            if (!lim) return sum;
          }
        }
        return sum;
      }
      LL zkw() {
        LL ret=0;
        while (spfa()) {
          memset(vis,0,sizeof(vis));
          memset(cur,0,sizeof(cur));
          ret+=dfs(S,INF)*dis[T];
        }
        return ret;
      }
    } G;
    
    int main(){
      scanf("%d %d",&n,&m);
      for (ri i=1;i<=n;i++) {
        scanf("%d %d %d %d",&a[i],&b[i],&c[i],&d[i]);
        preb[i]=b[i];
      }
      for (ri i=1;i<=m;i++) {
        scanf("%d %d",&u[i],&v[i]);
        b[u[i]]++; b[v[i]]++;
      }
      for (ri i=1;i<=n;i++) e[i]=a[i]+b[i];
      for (ri i=1;i<=m;i++) {
        G.add_edge(S,i,1,0);
        G.add_edge(i,m+u[i],1,0);
        G.add_edge(i,m+v[i],1,0);
      }
      for (ri i=1;i<=n;i++) {
        for (ri j=a[i];j+preb[i]<e[i];j++) G.add_edge(m+i,T,1,2*j*c[i]+c[i]-2*d[i]*e[i]+2*j*d[i]+d[i]);
      }
      LL ans=0;
      for (ri i=1;i<=n;i++) ans+=b[i]*b[i]*d[i]+a[i]*a[i]*c[i];
      ans+=G.zkw();
      cout<<ans<<endl;
    }
  • 相关阅读:
    array_map()与array_shift()搭配使用 PK array_column()函数
    Educational Codeforces Round 8 D. Magic Numbers
    hdu 1171 Big Event in HDU
    hdu 2844 poj 1742 Coins
    hdu 3591 The trouble of Xiaoqian
    hdu 2079 选课时间
    hdu 2191 珍惜现在,感恩生活 多重背包入门题
    hdu 5429 Geometric Progression 高精度浮点数(java版本)
    【BZOJ】1002: [FJOI2007]轮状病毒 递推+高精度
    hdu::1002 A + B Problem II
  • 原文地址:https://www.cnblogs.com/shxnb666/p/11286174.html
Copyright © 2011-2022 走看看