zoukankan      html  css  js  c++  java
  • codeforces863F Almost Permutation 费用流

    题目传送门

    题意:

      构造出一个数列,数字在$1~n$的范围内,要求$sum_{i=1}^n  count(i)^{2}$最小,$count(i)$的意思是数列中i出现的次数。并且数列要满足两种类型的条件,一个是$a_i->a_j$全部大于v,还有$a_i->a_j$全部小于v。

    思路:

      首先,我们可以把限制条件转化为某个位置上数值的上限和下限,然后位置和对应能填的所有数字都建容量为1的边,然后每一个数字向汇点建n条容量为1的边,费用分别是$1,3,5,……,2*j-1$,这样建边后,如果一个数字被选取了两次,得到的前缀和刚好就是出现次数的平方。

    #pragma GCC optimize (2)
    #pragma G++ optimize (2)
    #pragma comment(linker, "/STACK:102400000,102400000")
    #include<bits/stdc++.h>
    #include<cstdio>
    #include<vector>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    #define dep(i,b,a) for(int i=b;i>=a;i--)
    #define clr(a,b) memset(a,b,sizeof(a))
    #define pb push_back
    #define pii pair<int,int >
    using namespace std;
    typedef long long ll;
    const int maxn=200010;
    const int inf=0x3f3f3f3f;
    ll rd()
    {
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    #include<bits/stdc++.h>
    #define CLR(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll;
    const int MAXN = 1010;
    const int MAXM = 20010;
    const int INF = 0x3f3f3f3f;
    struct Edge {
        int to, next, cap, flow, cost;
    
    } edge[MAXM];
    struct pp{
        int u,v,c,w;
    }in[MAXN];
    int head[MAXN], tol;
    int pre[MAXN], dis[MAXN];
    bool vis[MAXN];
    int N=MAXN-2;
    int n,q,l[MAXN],r[MAXN];
    void init() {
    
        tol = 0;
        memset(head, -1, sizeof(head));
    
    }
    void addv(int u, int v, int cap, int cost) {
        edge[tol].to = v;
        edge[tol].cap = cap;
        edge[tol].cost = cost;
        edge[tol].flow = 0;
        edge[tol].next = head[u];
        head[u] = tol++;
        edge[tol].to = u;
        edge[tol].cap = 0;
        edge[tol].cost = -cost;
        edge[tol].flow = 0;
        edge[tol].next = head[v];
        head[v] = tol++;
    
    }
    bool spfa(int s, int t) {
        queue<int>q;
        clr(dis,INF);
        clr(vis,0),clr(pre,-1);
    
        dis[s] = 0;
        vis[s] = true;
        q.push(s);
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            vis[u] = false;
            for (int i = head[u]; i != -1; i = edge[i].next) {
                int v = edge[i].to;
    
                if (edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost) {
                    dis[v] = dis[u] + edge[i].cost;
                    pre[v] = i;
                    if (!vis[v]) {
                        vis[v] = true;
                        q.push(v);
    
                    }
    
                }
    
            }
    
        }
        if (pre[t] == -1)return false;
        else return true;
    
    }
    //返回的是最大流,cost 存的是最小费用
    int minCostMaxflow(int s, int t, int &cost) {
        int flow = 0;
        cost = 0;
        while (spfa(s, t)) {
            int Min = INF;
            for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to]) {
                if (Min > edge[i].cap - edge[i].flow)
                    Min = edge[i].cap - edge[i].flow;
    
            }
            for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to]) {
                edge[i].flow += Min;
                edge[i ^ 1].flow -= Min;
                cost += edge[i].cost * Min;
    
            }
            flow += Min;
    
        }
        return flow;
    
    }
    int main(){
        cin>>n>>q;
        init();
        int S=0,T=2*n+1;
        rep(i,1,n){
            addv(S,i,1,0);
            r[i]=n;
            l[i]=1;
            rep(j,1,n){
                addv(i+n,T,1,2*j-1);
            }
        }
        int flag=1;
        while(q--){
            int op,x,y,v;
            scanf("%d%d%d%d",&op,&x,&y,&v);
            if(op==1){
                rep(i,x,y){
                    l[i]=max(l[i],v);
                }
            }else{
                rep(i,x,y){
                    r[i]=min(r[i],v);
                }
            }
        }
        rep(i,1,n){
            if(l[i]>r[i]){
                flag=0;
                break;
            }
            rep(j,l[i],r[i]){
                addv(i,j+n,1,0);
            }
        }
        if(flag==0){
            puts("-1");
            return 0;
        }
        int c;
        minCostMaxflow(S,T,c);
        cout<<c<<endl;
        
    } 
  • 相关阅读:
    四大开源协议比较:BSD、Apache、GPL、LGPL
    LGPL 与GPL的区别
    【Python】Python Mako模板使用
    【Linux】shell判空
    【云计算】Docker容器不能修改hosts文件怎么解决?
    【Scala】Scala技术栈
    【Web】Rest && 权限管理 && LDAP && OAuth && Nginx && Lua 等
    【云计算】使用privilege权限对Docker内核参数进行定制
    【云计算】Docker 多进程管理方案
    【分布式计算】关于Hadoop、Spark、Storm的讨论
  • 原文地址:https://www.cnblogs.com/mountaink/p/11609772.html
Copyright © 2011-2022 走看看