zoukankan      html  css  js  c++  java
  • AT3672 mul

    一道比较有意思的网络流。
    把所有数的倍数连权为(inf)的边,
    然后把所有正数连汇点,所有负数连原点。
    最后减去最小割就是答案。
    易证。
    Code:

    #include <bits/stdc++.h>
      
    #define int long long 
    const int maxn = 110;
    const int inf = 0x3f3f3f3f;     
    typedef long long ll;
      
    int n, m, i, j, k, st, ed, cnte = 1;        
    ll hd[maxn], cur[maxn], a[maxn], dep[maxn];
    ll nxt[30000], ver[30000], wei[30000];
    ll ans;    
      
    template<class t> inline t _min(t a,t b) { return a < b ? a : b; }
    template<class t> inline void read(t& res) {
        res = 0;  char ch = getchar();  bool sign = 0;
        while(!isdigit(ch))
            sign |= ch == '-', ch = getchar();
        while(isdigit(ch))
            res = (res << 1) + (res << 3) + (ch & 15), ch = getchar();
        if(sign)
            res = -res;  
    }
      
    inline void adde(int u,int v,ll w) {
        ver[++cnte] = v;  nxt[cnte] = hd[u];  wei[cnte] = w;  hd[u] = cnte;
        ver[++cnte] = u;  nxt[cnte] = hd[v];  wei[cnte] = 0;  hd[v] = cnte;   
    }
      
    inline bool bfs() {
        std::queue<int> q;
        memset(dep,0,sizeof(dep));
        dep[st] = 1;  q.push(st);
        while(!q.empty()) {
            int u = q.front();  q.pop();
            for(int i = hd[u];~i;i = nxt[i]) {
                int v = ver[i];  ll w = wei[i];
                if(!dep[v] && w) {
                    dep[v] = dep[u] + 1;
                    q.push(v);  
                }
            }
        }
        return dep[ed];
    }
    ll dfs(int u,ll flow) {
        if(u == ed)
            return flow;
        ll dec = flow;
        for(ll& i = cur[u];~i && dec;i = nxt[i]) {
            int v = ver[i];  ll w = wei[i];   
            if(dep[u] + 1 == dep[v] && w) {
                int tmp = dfs(v,_min(w,dec));     
                dec -= tmp;       
                wei[i] -= tmp;   
                wei[i ^ 1] += tmp;
            }
        }
        return flow - dec;
    }
    inline void dinic() {
        while(bfs()) {
            memcpy(cur,hd,sizeof(hd));  ll flow;  
            while(flow = dfs(st,inf))
                ans -= flow;
        }
        return;  
    }
      
    signed main() {
        memset(hd,-1,sizeof(hd));
        read(n);            
        st = n + 1;  ed = n + 2;
        for(int i = 1;i <= n;i++) 
            read(a[i]);
        for(int i = 1;i <= n;i++) {
            if(a[i] >= 0)
                adde(i,ed,a[i]), ans += a[i];    
            else
                adde(st,i,-a[i]);
        }
        for(int i = 1;i <= n;i++) 
            for(int j = i << 1;j <= n;j += i)
                adde(i,j,inf); 
        dinic();   
        printf("%lld
    ",ans);    
        return 0;   
    }
    
  • 相关阅读:
    6.1 tar:打包备份
    6.3-4 zip、unzip
    6.5 scp:远程文件复制
    S7 Linux用户管理及用户信息查询命令
    7.6 passwd:修改用户密码
    7.2-5 usermod
    DES
    FreeRTOS笔记
    第4章 裸机系统和多任务系统
    第008课_第1个ARM落版程序及引申
  • 原文地址:https://www.cnblogs.com/Sai0511/p/11202580.html
Copyright © 2011-2022 走看看