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\n",ans);    
    return 0;   
}
posted @ 2019-07-17 17:46  _connect  阅读(129)  评论(0编辑  收藏  举报
Live2D