首页 > 其他分享 >闲话 22.12.8

闲话 22.12.8

时间:2022-12-08 22:00:48浏览次数:71  
标签:adde int 闲话 rep cin ++ 22.12 id

啊?你问最近为啥没有闲话?
嘛,首先是 NOIP 取消了!然后就滚回家搞 whk 了!回家来 whk 之余浅写了点杂东西,反正晚上没事可干(
突然发现句末不想加句号 句中不想加逗号(
主要是这种语气下感觉会很突兀(
于是就用空格和半括号(以及感叹号)代替了!
元气

现在属于是回来复建了(
然后跟进度嘛 今天是网络流(初等)!
我发现写了这些题 Dinic(s,t) 是根本没变化 所以粘在最开始的地方(

流杂题

不粘题面了。

Dinic
#include <bits/stdc++.h>
using namespace std; using pii = pair<int,int>; using vi = vector<int>; using ll = long long; 
using ull = unsigned long long; using db = double; using ld = long double; using lll = __int128_t;
mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
template <typename T> T rand(T l, T r) { return uniform_int_distribution<T>(l, r)(rnd); }
template <typename T1, typename T2> T1 min(T1 a, T2 b) { return a < b ? a : b; }
template <typename T1, typename T2> T1 max(T1 a, T2 b) { return a > b ? a : b; }
#define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define ufile(x) 
#define rep(i,s,t) for (register int i = (s), i##_ = (t) + 1; i < i##_; ++ i)
#define pre(i,s,t) for (register int i = (s), i##_ = (t) - 1; i > i##_; -- i)
#define Aster(i, s) for (int i = head[s], v; i; i = e[i].next)
#define all(s) s.begin(), s.end()
#define eb emplace_back
#define pb pop_back
#define em emplace
const int N = 2e6 + 5;
const int inf = 0x3f3f3f3f;
const ll infll = 0x3f3f3f3f3f3f3f3fll;

int head[2][N], mlc = 1;
struct ep {
    int to, next, flow;
} e[N << 1];
void adde(int u, int v, int f) {
    e[++ mlc] = { v, head[0][u], f };
    head[0][u] = mlc;
    e[++ mlc] = { u, head[0][v], 0 };
    head[0][v] = mlc; 
}

queue<int> que;
int dep[N]; 
bool bfs(int s, int t) {
    rep(i,1,M) dep[i] = 0, head[1][i] = head[0][i];
    que.push(s); dep[s] = 1;
    while (que.size()) {
        int u = que.front(); que.pop();
        for (int i = head[0][u], v; i; i = e[i].next) {
            v = e[i].to;
            if (e[i].flow and !dep[v]) {
                dep[v] = dep[u] + 1;
                que.push(v);
            }
        }
    } return dep[t];
}

int dfs(int u, int in, int t) {
    if (u == t) return in;
    int out = 0;
    for (int &i = head[1][u], v; i; i = e[i].next) {
        v = e[i].to;
        if (e[i].flow and dep[v] == dep[u] + 1) {
            int res = dfs(v, min(in, e[i].flow), t);
            if (res == 0) dep[v] = 0;
            in -= res, out += res;
            e[i].flow -= res, e[i ^ 1].flow += res;
            if (in == 0) break;
        }
    } return out;
}

int Dinic(int s, int t) {
    int ret = 0;
    while(bfs(s, t)) ret += dfs(s, 1e9, t);
    return ret;
}

[SCOI2007] 蜥蜴

标准拆出入点模型。

首先每个点的承载力用拆点解决。每个点拆成入点和出点,之间连边,流量是这根石柱能承受的蜥蜴数。然后我们就可以随意连边了,只需要保证指向该点的边连在入点,从该点出去的边连在出点即可。
随后就是显然的关系了。
首先由超级源点向各存在蜥蜴的点连边。然后能跳到的点间互相连边,能跳出去的点向超级汇点连边。
最后最大流就是能跳出去的最大蜥蜴数。

距离是欧氏距离。

code
int n, r, c, d, s, t, cnt, id[25][25][2];
char mat[25][25], pos[25][25];

bool inrange(int x1, int y1, int x2, int y2) {
    return (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) <= d * d;
}

signed main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> r >> c >> d;
    rep(i,1,r) cin >> mat[i] + 1;
    rep(i,1,r) cin >> pos[i] + 1;
    rep(i,1,r) rep(j,1,c) id[i][j][0] = ++ n, id[i][j][1] = ++ n;
    s = ++ n, t = ++ n;
    rep(i,1,r) rep(j,1,c) if (pos[i][j] == 'L') adde(s, id[i][j][0], 1), ++ cnt;
    rep(i,1,r) rep(j,1,c) if (mat[i][j] != 0) adde(id[i][j][0], id[i][j][1], mat[i][j] - '0');
    rep(i,1,r) rep(j,1,c) if (i <= d or i >= r - d + 1 or j <= d or j >= c - d + 1) adde(id[i][j][1], t, inf);
    rep(i,1,r) rep(j,1,c) rep(i2,1,r) rep(j2,1,c) if (i <= d or i >= r - d + 1 or j <= d or j >= c - d + 1) continue;
    else if (inrange(i, j, i2, j2)) adde(id[i][j][1], id[i2][j2][0], inf);
    cout << cnt - Dinic(s, t);
}



[SDOI2015]星际战争

标准二分判定模型。

我们假定目前需要判定一个时间是否可以将所有机器人都消灭。这时我们就已知了每个激光武器的最大攻击量。换句话说,我们就已知了从超级原点到每一个激光武器对应边的最大流量。
因此可以直接建图跑最大流。
建图显然,源点连向武器,边权二分得到,武器连向能瞄准到的机器人,可以无限输出,然后机器人连向终点,边权是机器人的血条。最后看一下是否最大流是机器人血条加和就行。

输出不要四舍五入。

code
int M, s, t, n, m, a[N], b[N], tot;
bool ck[55][55]; // 5

bool check(double tme) {
    rep(i,1,M) head[0][i] = 0; mlc = 1;
    rep(i,1,m) adde(s, i, b[i] * tme);
    rep(i,1,m) rep(j,1,n) if (ck[i][j]) adde(i, m + j, inf);
    rep(j,1,n) adde(m + j, t, a[j]);
    return fabs(Dinic(s, t) - tot) <= eps;
}

signed main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n >> m; M = n + m + 2; s = n + m + 1, t = n + m + 2;
    rep(i,1,n) cin >> a[i], tot += a[i];
    rep(i,1,m) cin >> b[i];
    rep(i,1,m) rep(j,1,n) cin >> ck[i][j];
    double l = 0, r = 1e4, mid;
    while ((r - l) > eps) {
        mid = (l + r) / 2;
        if (check(mid)) r = mid;
        else l = mid;
    } 
    printf("%.6lf", l);
}



P4311 士兵占领

最小 \(\to\) 最大模型。

最少个数的士兵不好最大流。那就转化成最大不放的士兵数。删掉一个士兵会让行列都减一,那让行列分别连在源汇点上,分别流量是该行/列能删掉的最大士兵数。然后在可以删士兵的位置连 \(1\) 的边。跑最大流即可。
总点数减不可以放的位置减跑出来的值就是最终答案。

记得减。

code
int M, s, t, n, m, k, l[N], c[N], t1, t2;
bool ck[105][105];

signed main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> m >> n >> k;
    rep(i,1,m) cin >> l[i], l[i] = n - l[i];
    rep(i,1,n) cin >> c[i], c[i] = m - c[i];
    rep(i,1,k) cin >> t1 >> t2, l[t1] --, c[t2] --, ck[t1][t2] = 1;
    rep(i,1,m) if (l[i] < 0) puts("JIONG!"), exit(0);
    rep(i,1,n) if (c[i] < 0) puts("JIONG!"), exit(0);
    s = n + m + 1, t = M = n + m + 2;
    rep(i,1,m) adde(s, i, l[i]);
    rep(i,1,n) adde(m + i, t, c[i]);
    rep(i,1,m) rep(j,1,n) if (!ck[i][j]) adde(i, j + m, 1);
    cout << n * m - Dinic(s, t) - k;
}



[HNOI2007] 紧急疏散

超级拆点模型。二分 + 拆点、

首先这玩意直接算答案是很麻烦的。因此考虑转换成判定。转成判定有好处:我们能知道每个门能拆出几个点来了。我们将一个门拆成[时间]个点,每个点向出边连 \(1\) 的边,向下一时间的门连 \(\infty\) 的边。这样只需要跑出每个点到每个门的路径长度就可以直接将一个点连在对应门的对应时间上。
跑最大流即可。

听说空间复杂度很大?不是很懂。

code
int M, s, t, n, m, sid[25][25], id[105][105], mx, cnt, pop, dis[25][25][25 * 25];
char gr[105][105], vis[25][25];
int dx[] = {0, 0, -1, 1}, dy[] = {-1, 1, 0, 0};

struct _tmp { int x, y, dis; _tmp(int x, int y, int d) : x(x), y(y), dis(d) {} };
queue<_tmp> q_t;

bool check(int tme) {
    rep(i,1,M) head[0][i] = 0; mlc = 1;
    M = tme * cnt + pop; s = ++ M, t = ++ M;
    rep(i,1,n) rep(j,1,m) if (gr[i][j] == '.') adde(s, sid[i][j], 1);
    rep(i,1,cnt) rep(j,1,tme) adde(pop + (i - 1) * tme + j, t, 1);
    rep(i,1,cnt) rep(j,1,tme-1) adde(pop + (i - 1) * tme + j, pop + (i - 1) * tme + j + 1, inf);
    rep(i,1,n) rep(j,1,m) if (gr[i][j] == '.') rep(k,1,cnt) if (dis[i][j][k] and dis[i][j][k] <= tme) 
        adde(sid[i][j], pop + (k - 1) * tme + dis[i][j][k], 1);
    return Dinic(s, t) == pop;
}

signed main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n >> m; 
    rep(i,1,n) cin >> gr[i] + 1;
    rep(i,1,n) rep(j,1,m) if (gr[i][j] == 'D') id[i][j] = ++ cnt;
    rep(i,1,n) rep(j,1,m) if (gr[i][j] == '.') {
        sid[i][j] = ++ pop;
        q_t.emplace(i, j, 0);
        memset(vis, 0, sizeof vis);
        vis[i][j] = 1;
        while (q_t.size()) {
            auto now = q_t.front(); q_t.pop();
            if (gr[now.x][now.y] == 'D') dis[i][j][ id[now.x][now.y] ] = now.dis;
            else rep(k,0,3) if (1 <= now.x + dx[k] and now.x + dy[k] <= n and 1 <= now.y + dy[k] and now.y + dy[k] <= m) 
                if (!vis[now.x + dx[k]][now.y + dy[k]] and gr[now.x + dx[k]][now.y + dy[k]] != 'X') 
                 vis[now.x + dx[k]][now.y + dy[k]] = 1, q_t.emplace(now.x + dx[k], now.y + dy[k], now.dis + 1);
        }
    } 
    int l = 0, r = 1000, mid;
    while (l <= r) {
        int mid = l + r >> 1;
        if (check(mid)) r = mid - 1;
        else l = mid + 1;
    } if (r == 1000) puts("impossible");
    else cout << r + 1 << '\n';
}



[SCOI2012]奇怪的游戏

染色经典模型。

首先假设我们将棋盘黑白染色,满足任意四联通的两个格子颜色不同。我们发现,每次肯定是在两个不同色的格子上 \(+1\)。因此如果两种颜色格子的数量相同,则必定有两种颜色格子的初始数字加和相同。假设最终变成的数是 \(x\),则我们有操作次数是 \(x * [格子的数量] - [初始数字加和]\)。又发现这个 \(x\) 可以二分,因为 \(x\) 可以达到则 \(x + 1\) 可以通过整体 \(+1\) 达到。二分的判定考虑网络流,我们能将黑白点建二分图,点与源汇点连边流量是点还需要操作的次数。随后我们将可以在一次操作中 \(+1\) 的黑白点链接流量无限的边,判定得到的答案是否能将所有点填满即可。
如果两种颜色格子数不相同,我们可以发现 \(x * [黑格子的数量] - [黑格子初始数字加和] = x * [白格子的数量] - [白格子初始数字加和]\),因为操作数肯定相同。这得到了 \(x = \frac{\text{[初始数字差值]}}{\text{[格子数量差值]}}\)。计算后做一次如上的判定即可。

inf 开大点。

code
int M, s, t, T, n, m, mx, n1, n2, s1, s2;
int a[45][45];
int dx[] = {0, 0, -1, 1}, dy[] = {-1, 1, 0, 0};

bool check(int mxv) {
    rep(i,1,M) head[0][i] = 0; mlc = 1;
    M = n * m; s = ++ M, t = ++ M;
    int val = 0;
    rep(i,1,n) rep(j,1,m) { 
        if ((i + j) & 1) {
            adde(s, (i - 1) * m + j, mxv - a[i][j]);
            val += mxv - a[i][j];
            rep(k,0,3) if (1 <= i + dx[k] and i + dx[k] <= n and 1 <= j + dy[k] and j + dy[k] <= m) 
                adde((i - 1) * m + j, (i + dx[k] - 1) * m + j + dy[k], inf);
        } else adde((i - 1) * m + j, t, mxv - a[i][j]);
    }
    return val == Dinic(s, t);
}

signed main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> T;
    while (T--) {
        n1 = n2 = s1 = s2 = mx = 0;
        cin >> n >> m; 
        rep(i,1,n) rep(j,1,m) cin >> a[i][j], mx = max(mx, a[i][j]);
        rep(i,1,n) rep(j,1,m) {
            if ((i + j) & 1) s1 += a[i][j], ++ n1;
            else s2 += a[i][j], ++ n2;
        }
        if (n1 == n2) {
            if (s1 != s2) cout << "-1\n";
            else {
                int l = mx, r = 2e9, mid;
                while (l <= r) {
                    mid = l + r >> 1;
                    if (check(mid)) r = mid - 1;
                    else l = mid + 1;
                } 
                if (r == 2e9) cout << "-1\n";
                else cout << (r + 1) * n1 - s1 << '\n';
            }
        } else {
            int x = (s1 - s2) / (n1 - n2);
            if (x < mx or !check(x)) cout << "-1\n";
            else cout << x * n1 - s1 << '\n';
        }
    }
}



happiness

经典最小割模型。

上一张同样很经典的图(图 from \(\text{FromATP}\)):
image

怎么样?会了吧!

我们要求最大贡献,那就转化成全部减最小贡献。
最小不行怎么做?这类题一般是二选一,那就源点表示选 \(1\),汇点表示选 \(0\),流量就是选 \(0/1\) 的贡献,每个点直接向源汇点连边。因为一个人不能选两个,这两条边不能都存在,总得删掉一条。这也就想到了最小割。我们割掉一条边表示选这条边对应的状态。
同时我们需要判定“两人共同选”。我们发现,这样总会是把一侧的边全割掉,另一侧都留着。那我们在割掉边的这一侧再拿一个新节点连上两人对应的节点,从这个点再连上割掉边一侧的超级源/汇点。连源汇点的边就设为两人共同选的贡献,这时由于两人共同选,也应该把这部分的贡献加上,这也契合了最小割的理念。

注意……没啥要注意的。

code
int M, s, t, n, m, ans, id[101][101];
int wen[101][101], li[101][101];
int rowwen[101][101], rowli[101][101];
int colwen[101][101], colli[101][101];

signed main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n >> m;
    rep(i,1,n) rep(j,1,m) cin >> wen[i][j], ans += wen[i][j];
    rep(i,1,n) rep(j,1,m) cin >> li[i][j], ans += li[i][j];
    rep(i,1,n-1) rep(j,1,m) cin >> rowwen[i][j], ans += rowwen[i][j];
    rep(i,1,n-1) rep(j,1,m) cin >> rowli[i][j], ans += rowli[i][j];
    rep(i,1,n) rep(j,1,m-1) cin >> colwen[i][j], ans += colwen[i][j];
    rep(i,1,n) rep(j,1,m-1) cin >> colli[i][j], ans += colli[i][j];
    s = ++ M, t = ++ M;
    rep(i,1,n) rep(j,1,m) {
        id[i][j] = ++ M;
        adde(s, id[i][j], wen[i][j]);
        adde(id[i][j], t, li[i][j]);
    }
    register int t1, t2, t3, t4;
    rep(i,1,n) rep(j,1,m) {
        if (i + 1 <= n) {
            t1 = id[i][j], t2 = id[i + 1][j], t3 = ++ M, t4 = ++ M; 
            adde(s, t3, rowwen[i][j]);
            adde(t3, t1, inf);
            adde(t3, t2, inf);
            adde(t1, t4, inf);
            adde(t2, t4, inf);
            adde(t4, t, rowli[i][j]);
        }
        if (j + 1 <= m) {
            t1 = id[i][j], t2 = id[i][j + 1], t3 = ++ M, t4 = ++ M;
            adde(s, t3, colwen[i][j]);
            adde(t3, t1, inf);
            adde(t3, t2, inf);
            adde(t1, t4, inf);
            adde(t2, t4, inf);
            adde(t4, t, colli[i][j]);
        }
    } 
    cout << ans - Dinic(s, t);
}

标签:adde,int,闲话,rep,cin,++,22.12,id
From: https://www.cnblogs.com/joke3579/p/chitchat221208.html

相关文章

  • Kubernetes学习笔记(四十二):CKA已通过2022.12.04
    考试版本:1.25.2注意点:使用PSI内远程浏览器,可以多开tab,但不能导入书签,需要自己搜索,所以请熟悉完整命令和yaml格式考前请仔细阅读考试手册(预约考试页面有链接),特别是熟悉......
  • PTA-oop第三次博客2022.12.4
    一.前言 题目集六:本次大作业是第一次写电信计费,难度较前几次的多边形有了明显的下降,题目难点不再是算法的设计,而是类与类之间关系的设计,同样也是因为第一次写电信计......
  • 【日总结】2022.12.5
    学了一周whk,滚回来OI了。今天啥都没干,颓了一天。[ARC152E]XorAnnihilation感觉很强。题目看起来很复杂,所以我们要想办法转换题意。注意到所有的值异或和为\(0\),......
  • lazarus 修正集合(2022.12.03)
    1.修正日期分隔符乱码(linux)https://www.cnblogs.com/qiufeng2014/p/16343424.html2.修复lazaruslinux(ubuntu/银河麒麟)ObjectInspector、使用combobox、colorbox等控......
  • 11.25 闲话
    今天去了师大附中。好难过,很感慨,回家路上想了很多。想了想还是明天结束后再写吧,有空补个回忆录。来更新了。去试机的路上和jzp坐在一起看b站,不免感叹时光飞逝,两年......
  • 闲话-
    写在前边:攻击性是相对而言的。对于说话的攻击性,没有,大可不必称之为对人的教训,有人认为这是显然的。我觉得..这是不显然的。攻击性你大可跳过去看下一节。一个整体......
  • 11.23 闲话
    啥都没干都要被骂,一个接一个来吵我,还觉得自己有道理?对对对我是不能有负面情绪的,不能在你面前表现出负面情绪,为啥不想想我高一整个人自闭了是谁导致的啊?是不是你啊?凭啥我要......
  • 11.22 闲话
    感觉物理要做笔记了,至少要把一些经典的计算结果记下来,今天做导练算得有点慢。。。其实一直想补一下数理化的笔记的,但是想了一下有好多内容,于是摆了。我从小到大就没有记笔......
  • 闲话 22.11.22
    闲话这个?突然没什么好说的了今天模拟赛让我体验了别人csp的四分之三别人:看T2。哦,会了。看T1。哦,会了。看T3。哦,会了。看T4。哦,会了。好像AK了,非常感动。我今天:看T......
  • 11.20 闲话
    复课两天,再上三天网课,所以有时间更新了,读书笔记可以摆了。但是周围好像就我在开香槟,班上同学似乎都不想网课。反转了,只有仓山区同学要网课。刚刚写完自由天地,感觉写文章......