In mathematics you don't understand things, you just get used to them.

标签 flows 下的文章

link。

good题,考虑像 国家集训队 - happiness 一样在棋盘上搞染色,我毛张 @shadowice1987 的图给你看啊

你像这样奇数层以 red -> blue -> green -> yellow 为一个周期,偶数层 yellow -> green -> blue -> red,就会发现给出的形状都包括恰好四种颜色和一条黑线。那现在就好搞了,就是要在每个连通块里面删除至少一种颜色的全部方块(包括黑线),有这样几种选择:全绿 / 全黄 / 全黑线(即破环红或蓝中的一个),像图右侧一样建图就好了。

#include<bits/stdc++.h>
using namespace std;
enum Color { red=1,blue,yellow,green };
const long long INF=0x3f3f3f3f;
template<class Kap> struct Net {
    const long long n;
    struct Arc {
        long long to, rev; Kap cap;
    };
    vector<long long> lev,iter;
    vector<vector<Arc>> e;
    std::queue<long long> q;
    Net(long long n):n(n),e(n),lev(n),iter(n) {}
    void add(long long one,long long ano,Kap cap) {
        // printf("  %lld  %lld  %lld\n",one,ano,cap);
        e[one-1].push_back((Arc){ano-1,(long long)(e[ano-1].size())+(one==ano),cap});
        e[ano-1].push_back((Arc){one-1,(long long)(e[one-1].size())-1,0});
    }
    Kap solve(long long s,long long t) { return solve(s-1,t-1,std::numeric_limits<Kap>::max()); }
    bool Getlayer(long long s,long long t) {
        lev.assign(n,0);
        while(q.size())    q.pop();
        lev[s]=1;
        q.emplace(s);
        while(q.size()) {
            long long now=q.front();
            q.pop();
            if(now==t)    break;
            for(long long i=0; i<(long long)(e[now].size()); ++i) {
                long long y=e[now][i].to; Kap cap=e[now][i].cap;
                if(!lev[y] && cap)    lev[y]=lev[now]+1,q.emplace(y);
            }
        }
        return lev[t];
    };
    Kap Augment(long long now,Kap up,long long t) {
        if(now==t)    return up;
        Kap rlow=0;
        for(long long& i=iter[now]; i<(long long)(e[now].size()); ++i) {
            if(!up)    break;
            long long y=e[now][i].to; Kap& cap=e[now][i].cap;
            if(lev[y]==lev[now]+1 && cap) {
                Kap f=Augment(y,min(up,cap),t);
                if(f<=0)    continue;
                cap-=f; e[y][e[now][i].rev].cap+=f; up-=f; rlow+=f;
            }
        }
        if(!rlow)    lev[now]=n+1;
        return rlow;
    };
    Kap solve(long long s,long long t,const Kap inf) {
        lev.assign(n,0); iter.assign(n,0); Kap res=0,tmp;
        while (Getlayer(s,t)) {
            iter.assign(n, 0);
            if((tmp=Augment(s,inf,t)))    res+=tmp;
            else    break;
        }
        return res;
    }
};
long long r,c,n,celx[100100],cely[100100],celw[100100],S,T,co[100100];
map<long long,long long> mp;
bool valid(long long x,long long y) { return x>=1 && x<=r && y>=1 && y<=c; }
long long getid(long long x,long long y) { return 1ll*(x-1)*c+y; }
signed main() {
    scanf("%lld %lld %lld",&c,&r,&n);
    for(long long i=1; i<=n; ++i)    scanf("%lld %lld %lld",&cely[i],&celx[i],&celw[i]),mp[getid(celx[i],cely[i])]=i;
    // for(long long i=1; i<=n; ++i)    printf("  ---- %lld %lld %lld\n",celx[i],cely[i],celw[i]);
    for(long long i=1; i<=n; ++i) {
        if(cely[i]%4==0)    co[i]=(celx[i]&1)?3:1;
        else if(cely[i]%4==1)    co[i]=(celx[i]&1)?1:3;
        else if(cely[i]%4==2)    co[i]=(celx[i]&1)?2:4;
        else    co[i]=(celx[i]&1)?4:2;
    }
    // char tmp[5][10]={"tmp","red","blue","yellow","green"};
    // for(long long i=1; i<=n; ++i)    puts(tmp[co[i]]);
    // for(long long i=1; i<=n; ++i)    printf(" %lld",co[i]);
    // puts("");
    // 1 for red, 2 for blue, 3 for yellow, 4 for green
    Net<long long> G(n+2); S=n+1; T=n+2;
    for(long long i=1; i<=n; ++i) {
        if(co[i]==yellow /*yellow*/) {
            G.add(S,i,celw[i]);
            if(valid(celx[i],cely[i]-1)) {
                long long j=mp[getid(celx[i],cely[i]-1)];
                if(j && co[j]==red)    G.add(i,j,INF);
            }
            if(valid(celx[i],cely[i]+1)) {
                long long j=mp[getid(celx[i],cely[i]+1)];
                if(j && co[j]==red)    G.add(i,j,INF);
            }
            // printf(" --- %lld %lld\n",celx[i],cely[i]);
            if(valid(celx[i]-1,cely[i])) {
                long long j=mp[getid(celx[i]-1,cely[i])];
                if(j && co[j]==red)    G.add(i,j,INF);
            }
            if(valid(celx[i]+1,cely[i])) {
                long long j=mp[getid(celx[i]+1,cely[i])];
                if(j && co[j]==red)    G.add(i,j,INF);
            }
        }
        else if(co[i]==green /*green*/) {
            G.add(i,T,celw[i]);
            if(valid(celx[i],cely[i]-1)) {
                long long j=mp[getid(celx[i],cely[i]-1)];
                if(j && co[j]==blue)    G.add(j,i,INF);
            }
            if(valid(celx[i],cely[i]+1)) {
                long long j=mp[getid(celx[i],cely[i]+1)];
                if(j && co[j]==blue)    G.add(j,i,INF);
            }
            if(valid(celx[i]+1,cely[i])) {
                long long j=mp[getid(celx[i]+1,cely[i])];
                if(j && co[j]==blue)    G.add(j,i,INF);
            }
            if(valid(celx[i]-1,cely[i])) {
                long long j=mp[getid(celx[i]-1,cely[i])];
                if(j && co[j]==blue)    G.add(j,i,INF);
            }
        }
        else if(co[i]==red) {
            if(valid(celx[i],cely[i]+1)) {
                long long j=mp[getid(celx[i],cely[i]+1)];
                // if(celx[i]==1 && cely[i]==1 && j)    printf("  --  %lld %lld %lld %lld %lld\n",celx[i],cely[i],celw[i],getid(celx[i],cely[i]),mp[getid(celx[i],cely[i])]);
                if(j && co[j]==blue)    G.add(i,j,min(celw[i],celw[j]));
            }
            if(valid(celx[i],cely[i]-1)) {
                long long j=mp[getid(celx[i],cely[i]-1)];
                // if(celx[i]==1 && cely[i]==1 && j)    printf("  --  %lld %lld %lld %lld %lld\n",celx[i],cely[i],celw[i],getid(celx[i],cely[i]),mp[getid(celx[i],cely[i])]);
                if(j && co[j]==blue)    G.add(i,j,min(celw[i],celw[j]));
            }
            if(valid(celx[i]+1,cely[i])) {
                long long j=mp[getid(celx[i]+1,cely[i])];
                // if(celx[i]==1 && cely[i]==1 && j)    printf("  --  %lld %lld %lld %lld %lld\n",celx[i],cely[i],celw[i],getid(celx[i],cely[i]),mp[getid(celx[i],cely[i])]);
                if(j && co[j]==blue)    G.add(i,j,min(celw[i],celw[j]));
            }
            if(valid(celx[i]-1,cely[i])) {
                long long j=mp[getid(celx[i]-1,cely[i])];
                // if(celx[i]==1 && cely[i]==1 && j)    printf("  --  %lld %lld %lld %lld %lld\n",celx[i],cely[i],celw[i],getid(celx[i],cely[i]),mp[getid(celx[i],cely[i])]);
                if(j && co[j]==blue)    G.add(i,j,min(celw[i],celw[j]));
            }
        }
    }
    printf("%lld\n",G.solve(S,T));
    return 0;
}

link。

Pretty nice practice for the min-cut trick.

Starting out we eliminate the constraint that if five students in a edge-connected component alternatively choose exactly the same learning branch they get an extra contribution to the answer, and easily we can work it out with the following way to build a network and run a max-flow algorithm:

  • Connect the source with each student and set the capacities of arcs as the number of euphorias the student would get if he or she chooses Arts.
  • Connect each student with the sink and set capacities of arcs as the number of euphorias the student would get if he or she chooses Science.

Considering how to deal with the extra contributions, we simply shrink the four neighboring students and the student himself or herself into one point and connect the source with this taken the extra contributions (for choosing Arts) as the capacities. Additionally, connect the point with the four neighboring students taken $+\infty$ as the capacities. So do we process ones who choose Science.

Just as the picture via @jun头吉吉 goes.

#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
template<typename Kap> struct Net {
    const int n;
    struct Arc {
        int to; size_t rev; Kap cap,flow;
    };
    vector<vector<Arc>> e;
    vector<int> iter,lev;
    queue<int,list<int>> q;
    Net(int n):n(n),e(n),iter(n),lev(n) {}
    void line(int one,int ano,Kap ca) {
        one--; ano--;
        assert(0<=one && one<n && 0<=ano && ano<n);
        e[one].push_back((Arc){ano,e[ano].size()+(one==ano),ca,0});
        e[ano].push_back((Arc){one,e[one].size()-1,0,0});
    }
    Kap dinitz(int s,int t) { return dinitz(s-1,t-1,numeric_limits<Kap>::max()); }
    bool Getlayer(int s,int t) {
        lev.assign(n,0); q.push(s); lev[s]=1;
        while(q.size()) {
            int now=q.front(); q.pop();
            for(int i=0; i<int(e[now].size()); ++i) {
                int y=e[now][i].to;
                if(!lev[y] && e[now][i].cap>e[now][i].flow)    lev[y]=lev[now]+1,q.push(y);
            }
        }
        return lev[t];
    }
    Kap Augment(int now,Kap up,int t) {
        if(now==t)    return up;
        Kap rlow=0;
        for(int& i=iter[now]; i<int(e[now].size()); ++i) {
            if(up==rlow)    break;
            int y=e[now][i].to;
            if(lev[y]==lev[now]+1 && e[now][i].cap>e[now][i].flow) {
                Kap f=Augment(y,min(up-rlow,e[now][i].cap-e[now][i].flow),t);
                e[now][i].flow+=f; e[y][e[now][i].rev].flow-=f; rlow+=f;
            }
        }
        if(up==rlow)    lev[now]=0;
        return rlow;
    }
    Kap dinitz(int s,int t,const Kap INF) {
        assert(0<=s && s<n && 0<=t && t<n);
        Kap res=0;
        while(Getlayer(s,t))    iter.assign(n,0),res+=Augment(s,INF,t);
        return res;
    }
};
int n,m,a[200][200],b[200][200],exta[200][200],extb[200][200],S,T,sum;
int valid(int x,int y) { return x>=1 && x<=n && y>=1 && y<=m; }
int getID(int x,int y) { return (x-1)*m+y; }
int artify(int x) { return x+n*m; }
int sciencify(int x) { return x+n*m*2; }
signed main() {
    scanf("%d %d",&n,&m);
    for(int i=1; i<=n; ++i) {
        for(int j=1; j<=m; ++j)    scanf("%d",&a[i][j]),sum+=a[i][j];
    }
    for(int i=1; i<=n; ++i) {
        for(int j=1; j<=m; ++j)    scanf("%d",&b[i][j]),sum+=b[i][j];
    }
    for(int i=1; i<=n; ++i) {
        for(int j=1; j<=m; ++j)    scanf("%d",&exta[i][j]),sum+=exta[i][j];
    }
    for(int i=1; i<=n; ++i) {
        for(int j=1; j<=m; ++j)    scanf("%d",&extb[i][j]),sum+=extb[i][j];
    }
    Net<int> net(n*m*3+2); S=n*m*3+1; T=n*m*3+2;
    for(int i=1; i<=n; ++i) {
        for(int j=1; j<=m; ++j) {
            net.line(S,getID(i,j),a[i][j]);
            net.line(getID(i,j),T,b[i][j]);
            net.line(S,artify(getID(i,j)),exta[i][j]);
            net.line(artify(getID(i,j)),getID(i,j),INF);
            net.line(getID(i,j),sciencify(getID(i,j)),INF);
            net.line(sciencify(getID(i,j)),T,extb[i][j]);
            if(valid(i+1,j)) {
                net.line(artify(getID(i,j)),getID(i+1,j),INF);
                net.line(getID(i+1,j),sciencify(getID(i,j)),INF);
            }
            if(valid(i,j+1)) {
                net.line(artify(getID(i,j)),getID(i,j+1),INF);
                net.line(getID(i,j+1),sciencify(getID(i,j)),INF);
            }
            if(valid(i-1,j)) {
                net.line(artify(getID(i,j)),getID(i-1,j),INF);
                net.line(getID(i-1,j),sciencify(getID(i,j)),INF);
            }
            if(valid(i,j-1)) {
                net.line(artify(getID(i,j)),getID(i,j-1),INF);
                net.line(getID(i,j-1),sciencify(getID(i,j)),INF);
            }
        }
    }
    printf("%d\n",sum-net.dinitz(S,T));
    return 0;
}

应该是最近最水的 ABC 了吧。

「ABC 205A」kcal

Link.

#include <bits/stdc++.h>
using ll = long long;
#define all(x) (x).begin(), (x).end()
int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    ll a, b;
    std::cin >> a >> b;
    std::cout << b * a / 100.0 << "\n";
    return 0;
}

「ABC 205B」Permutation Check

Link.

排序 / std::set 均可。

#include <bits/stdc++.h>
using ll = long long;
#define all(x) (x).begin(), (x).end()
int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int n, cur = 0;
    std::cin >> n;
    std::vector<int> a(n);
    for (int &x : a) {
        std::cin >> x;
        --x;
    }
    std::sort(all(a));
    for (int x : a) {
        if (cur != x) {
            std::cout << "No\n";
            return 0;
        }
        ++cur;
    }
    std::cout << "Yes\n";
    return 0;
}

「ABC 205C」POW

Link.

若 $c$ 为偶数则 $a:=|a|,b:=|b|$,然后比较 $a,b$ 大小即可。

#include <bits/stdc++.h>
using ll = long long;
#define all(x) (x).begin(), (x).end()
int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int a, b, c;
    std::cin >> a >> b >> c;
    if (c % 2 == 0) {
        a = std::abs(a);
        b = std::abs(b);
    }
    if (a > b) std::cout << ">\n";
    else if (a < b) std::cout << "<\n";
    else std::cout << "=\n";
    return 0;
}

「ABC 205D」Kth Excluded

Link.

预处理每一个数空出来的位置,然后询问时二分分类讨论。

#include <bits/stdc++.h>
using ll = long long;
#define all(x) (x).begin(), (x).end()
int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int n, q;
    std::cin >> n >> q;
    std::vector<ll> a(n), b(n);
    for (ll &x : a) std::cin >> x;
    for (size_t i = 0; i < a.size(); ++i) b[i] = a[i] - i - 1;
    for (ll k; q; --q) {
        std::cin >> k;
        ll pos = std::lower_bound(all(b), k) - b.begin();
        if (pos == n) std::cout << a.back() + k - b.back() << "\n";
        else std::cout << a[pos] - b[pos] + k - 1 << "\n";
    }
    return 0;
}

「ABC 205E」White and Black Balls

Link.

答案显然是 $\binom{n+m}{n}-\binom{n+m}{n-k-1}$。

#include <bits/stdc++.h>
using ll = long long;
#define all(x) (x).begin(), (x).end()
int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    constexpr int MOD = 1e9 + 7;
    int n, m, k;
    std::cin >> n >> m >> k;
    std::vector<ll> fac(n + m + 1), ifac(n + m + 1);
    auto pow = [&] (ll x, int y) {
        ll res = 1;
        for (; y; y >>= 1, x = x * x % MOD)
            if (y & 1) res = res * x % MOD;
        return (res + MOD) % MOD;
    };
    fac[0] = ifac[0] = 1;
    for (int i = 1; i < n + m + 1; ++i) {
        fac[i] = fac[i - 1] * i % MOD;
        ifac[i] = pow(fac[i], MOD - 2);
    }
    auto C = [&] (int n, int k) {return n < k ? 0 : fac[n] * ifac[n - k] % MOD * ifac[k] % MOD;};
    if (n - m > k) std::cout << "0\n";
    else std::cout << (C(n + m, n) - C(n + m, n - k - 1) + MOD) % MOD << "\n"; 
    return 0;
}

「ABC 205F」Grid and Tokens

Link.

网络流板题。

#include <bits/stdc++.h>
#include <atcoder/maxflow>
using ll = long long;
#define all(x) (x).begin(), (x).end()
int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int h, w, n;
    std::cin >> h >> w >> n;
    std::vector<std::vector<int>> obj(n, std::vector<int>(2));
    std::vector<int> row(h), col(w);
    auto id = [&] () {
        static int cnt = 0;
        return cnt++;
    };
    const int S = id(), T = id();
    for (int &x : row) x = id();
    for (int &x : col) x = id();
    for (std::vector<int> &x : obj) x = std::vector<int>({id(), id()});
    atcoder::mf_graph<int> G(id());
    for (int x : row) G.add_edge(S, x, 1);
    for (int x : col) G.add_edge(x, T, 1);
    for (int i = 0; i < n; ++i) {
        int a, b, c, d;
        std::cin >> a >> b >> c >> d;
        --a, --b;
        G.add_edge(obj[i][0], obj[i][1], 1);
        for (int j = a; j < c; ++j) G.add_edge(row[j], obj[i][0], 1);
        for (int j = b; j < d; ++j) G.add_edge(obj[i][1], col[j], 1);
    }
    std::cout << G.flow(S, T) << "\n";
    return 0;
}

Description

Link.

一年一度的综艺节目《中国新代码》又开始了。Zayid 从小就梦想成为一名程序员,他觉得这是一个展示自己的舞台,于是他毫不犹豫地报名了。

轻车熟路的 Zayid 顺利地通过了海选,接下来的环节是导师盲选,这一阶段的规则是这样的:
总共 $n$ 名参赛选手(编号从 $1$ 至 $n$)每人写出一份代码并介绍自己的梦想。接着由所有导师对这些选手进行排名。为了避免后续的麻烦,规定不存在排名并列的情况。

同时,每名选手都将独立地填写一份志愿表,来对总共 $m$ 位导师(编号从 $1$ 至 $m$)作出评价。志愿表上包含了共 $m$ 档志愿。对于每一档志愿,选手被允许填写最多 $C$ 位导师,每位导师最多被每位选手填写一次(放弃某些导师也是被允许的)。

在双方的工作都完成后,进行录取工作。每位导师都有自己战队的人数上限,这意味着可能有部分选手的较高志愿、甚至是全部志愿无法得到满足。

节目组对 ‘‘前 $i$ 名的录取结果最优’’ 作出如下定义:

  • 前 $1$ 名的录取结果最优,当且仅当第 $1$ 名被其最高非空志愿录取(特别地,如果第 $1$ 名没有填写志愿表,那么该选手出局)。
  • 前 $i$ 名的录取结果最优,当且仅当在前 $i − 1$ 名的录取结果最优的情况下:第 $i$ 名被其理论可能的最高志愿录取(特别地,如果第 $i$ 名没有填写志愿表、或其所有志愿中的导师战队均已员,那么该选手出局)。

如果一种方案满足 ‘‘前 $n$ 名的录取结果最优’’,那么我们可以简称这种方案是最优的。

举例而言,$2$ 位导师 T 老师、F 老师的战队人数上限分别都是 $1$ 人;$2$ 位选手 Zayid、DuckD 分列第 $1$、$2$ 名。那么下面 $3$ 种志愿表及其对应的最优录取结果如表中所示:

选手第 $1$ 志愿第 $2$ 志愿录取志愿加入战队
ZayidN/AT 老师、F 老师2F 老师
DuckDT 老师F 老师1T 老师
选手第 $1$ 志愿第 $2$ 志愿录取志愿加入战队
ZayidT 老师F 老师1T 老师
DuckDT 老师F 老师2F 老师
选手第 $1$ 志愿第 $2$ 志愿录取志愿加入战队
ZayidF 老师N/A1F 老师
DuckDF 老师N/A出局N/A

可以证明,对于上面的志愿表,对应的方案都是唯一的最优录取结果。
每个人都有一个自己的理想值 $s_i$,表示第 $i$ 位同学希望自己被第 $s_i$ 或更高的志愿录
取,如果没有,那么他就会非常沮丧。
现在,所有选手的志愿表和排名都已公示。巧合的是,每位选手的排名都恰好与它
们的编号相同。
对于每一位选手,Zayid 都想知道下面两个问题的答案:

  • 在最优的录取方案中,他会被第几志愿录取。
  • 在其他选手相对排名不变的情况下,至少上升多少名才能使得他不沮丧。
    作为《中国新代码》的实力派代码手,Zayid 当然轻松地解决了这个问题。不过他
    还是想请你再算一遍,来检验自己计算的正确性。

你可能注意到了根本没有概括因为太 tm 长了妈妈我不想概括

Solution

这份题面真难读。

对于第一问,网络流;

我们把学生和导师分别放到左右两列弄成一个二分图.

源点连容量为 $1$ 的学生边,然后让第一个学生连第一志愿,容量为 $1$,如果能流量有增就下一个,否则删除这条边下一个;

导师往汇点连人数限制的边。

对于第二问,同样网络流。

每个学生二分其最终排名,若学生 $x$ 的最终排名为 $k$,就用第一问的条件把 $x-k-1$ 名学生的边连上看是否满流。

#include<bits/stdc++.h>
const int INF=1e9;
std::queue<int> q;
std::vector<int> a[210][210];
int n,m,head[90010],nxt[180010],to[180010],cap[180010],Cur[900010],dep[900010],src,snk,cntot=1,up[210],s[210],ans[210];
void addEdge(int one,int ano,int val)
{
    to[++cntot]=ano;
    cap[cntot]=val;
    nxt[cntot]=head[one];
    head[one]=cntot;
    
    to[++cntot]=one;
    cap[cntot]=0;
    nxt[cntot]=head[ano];
    head[ano]=cntot;
}
bool MF_bfs()
{
    for(int i=1;i<=n+m+2;++i)
    {
        Cur[i]=head[i];
        dep[i]=INF;
    }
    q.push(src);
    dep[src]=1;
    while(!q.empty())
    {
        int now=q.front();
        q.pop();
        for(int i=head[now];i;i=nxt[i])
        {
            int y=to[i];
            if(cap[i] && dep[y]==INF)
            {
                dep[y]=dep[now]+1;
                q.push(y);
            }
        }
    }
    return dep[snk]^INF;
}
int MF_dfs(int x,int in)
{
    if(x==snk)    return in;
    else
    {
        int out=0;
        for(int &i=Cur[x];i;i=nxt[i])
        {
            int y=to[i];
            if(cap[i] && dep[y]==dep[x]+1)
            {
                int tmp=MF_dfs(y,std::min(in,cap[i]));
                cap[i]-=tmp;
                cap[i^1]+=tmp;
                in-=tmp;
                out+=tmp;
                if(!in)    break;
            }
        }
        if(!out)    dep[x]=INF;
        return out;
    }
}
int Dinic()
{
    int res=0;
    while(MF_bfs())    res+=MF_dfs(src,INF);
    return res;
}
bool check(int x,int all)
{
    cntot=1;
    for(int i=1;i<=n+m+2;++i)    head[i]=0;
    addEdge(src,x,1);
    for(int i=1;i<=m;++i)    addEdge(n+i,snk,up[i]);
    int low=0;
    for(int i=1;i<all;++i)
    {
        addEdge(src,i,1);
        if(ans[i])
        {
            for(int now:a[i][ans[i]])    addEdge(i,n+now,1);
        }
        else    ++low;
    }
    for(int i=1;i<=s[x];++i)
    {
        for(int now:a[x][i])    addEdge(x,now+n,1);
    }
    return low+Dinic()==all;
}
int search(int l,int r)
{
    int res=r+1,ID=r+1;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(check(ID,ID-mid))
        {
            res=mid;
            r=mid-1;
        }
        else    l=mid+1;
    }
    return res;
}
void Go()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=m;++i)    scanf("%d",&up[i]);
    for(int i=1;i<=n;++i)
    {
        for(int j=1,x;j<=m;++j)
        {
            scanf("%d",&x);
            if(x)    a[i][x].emplace_back(j);
        }
    }
    for(int i=1;i<=n;++i)    scanf("%d",&s[i]);
    
    src=n+m+1;
    snk=n+m+2;
    for(int i=1;i<=m;++i)    addEdge(n+i,snk,up[i]);
    for(int i=1;i<=n;++i)
    {
        addEdge(src,i,1);
        for(int j=1;j<=m;++j)
        {
            if(!a[i][j].empty())
            {
                for(int now:a[i][j])    addEdge(i,now+n,1);
                if(MF_bfs())
                {
                    int waste=MF_dfs(src,INF);
                    ans[i]=j;
                    break;
                }
                else
                {
                    int cur=cntot;
                    for(int k=1;k<=int(a[i][j].size());++k)
                    {
                        cap[cur]=cap[cur^1]=0;
                        cur-=2;
                    }
                }
            }
        }
    }
    
    for(int i=1;i<=n;++i)
    {
        if(ans[i])    printf("%d ",ans[i]);
        else    printf("%d ",m+1);
    }
    printf("\n");
    
    for(int i=1;i<=n;++i)
    {
        if(ans[i] && ans[i]<=s[i])    printf("0 ");
        else    printf("%d ",search(1,i-1));
    }
    printf("\n");
    
    for(int i=1;i<=n+m+2;++i)    head[i]=0;
    for(int i=1;i<=n;++i)    ans[i]=0;
    for(int i=1;i<=n;++i)
    {
        for(int j=1;j<=m;++j)    a[i][j].clear();
    }
    cntot=1;
}
int main()
{
    int T,waste;
    scanf("%d %d",&T,&waste);
    while(T-->0)    Go();
    return 0;
}

「ABC 193A」Discount

Link.

略。

#include<cstdio>
int main()
{
    int a,b;
    scanf("%d %d",&a,&b);
    printf("%.2f\n",(1.0-(double)b/(double)a)*100.0);
    return 0;
}

「ABC 193B」Play Snuke

Link.

排序。

#include<cstdio>
#include<algorithm>
using namespace std;
struct node
{
    int tim,pay,ps;
}nodes[100010];
bool cmp(node one,node ano)
{
    return one.pay<ano.pay;
}
int ans=-1;
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;++i)    scanf("%d %d %d",&nodes[i].tim,&nodes[i].pay,&nodes[i].ps);
    sort(nodes+1,nodes+n+1,cmp);
    for(int i=1;i<=n;++i)
    {
        if(((int)((double)nodes[i].tim-0.5)+1)<nodes[i].ps)
        {
            ans=nodes[i].pay;
            break;
        }
    }
    printf("%d\n",ans);
    return 0;
}

「ABC 193C」Unexpressed

Link.

可以容斥,也可以暴力枚举 std::set 去重。

#include<set>
#include<iostream>
#define int long long
using namespace std;
set<int> app;
signed main()
{
    int n,ians=0;
    cin>>n;
    for(int i=2;i*i<=n;++i)
    {
        for(int j=i*i;j<=n;j*=i)
        {
            if(!app.count(j))
            {
                ++ians;
                app.insert(j);
            }
        }
    }
    cout<<n-ians;
    return 0;
}

「ABC 193D」Poker

Link.

开个答案+单位贡献的结构体,然后模拟。

#include<iostream>
#include<iomanip>
using namespace std;
#define int long long
#define ID(c) ((c)-'0')
int k,num[20];
char s[20],t[20];
struct node
{
    int iths[20],sum,c[20];
    int spow(int fur)
    {
        int res=1;
        for(int i=1;i<=fur;++i)    res*=10;
        return res;
    }
    void getscor(char x[])
    {
        for(int i=1;i<=4;++i)    ++c[ID(x[i])];
        for(int i=1;i<=9;++i)
        {
            iths[i]=i*spow(c[i]);
            sum+=iths[i];
        }
    }
    void Op(int pos,int delta)
    {
        c[pos]+=delta;
        sum-=iths[pos];
        if(~delta)    iths[pos]*=10;
        else    iths[pos]/=10;
        sum+=iths[pos];
    }
}tak,aok;
signed main()
{
        ios::sync_with_stdio(false);
        cin.tie(0);
        cout.tie(0);
    cin>>k>>(s+1)>>(t+1);
    for(int i=1;i<=9;++i)    num[i]=k;
    for(int i=1;i<=4;++i)    --num[ID(s[i])],--num[ID(t[i])];
    tak.getscor(s);
    aok.getscor(t);
    int winans=0,allans=0;
    for(int i=1;i<=9;++i)
    {
        for(int j=1;j<=9;++j)
        {
            tak.Op(i,1);
            aok.Op(j,1);
            if(tak.sum>aok.sum)
            {
                if(i^j)    winans+=num[i]*num[j];
                else    winans+=num[i]*(num[j]-1);
            }
            tak.Op(i,-1);
            aok.Op(j,-1);
        }
    }
    for(int i=1;i<=9;++i)
    {
        for(int j=1;j<=9;++j)
        {
            if(i^j)    allans+=num[i]*num[j];
            else    allans+=num[i]*(num[j]-1);
        }
    }
    cout<<fixed<<setprecision(6)<<(double)winans/(double)allans<<endl;
    return 0;
}

「ABC 193E」Oversleeping

Link.

开始想到计算几何去了,打了很久。

实际上因为 $500$ 的范围,你可以直接枚举余数然后 exCRT 合并。

#include<cstdio>
#include<climits>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL INF=LONG_LONG_MAX;
namespace NumbTheo
{
    LL ftimes(LL bas,LL fur,LL mod)
    {
        LL res=0;
        while(fur)
        {
            if(fur&1)    res=(res+bas)%mod;
            bas=(bas+bas)%mod,fur>>=1;
        }
        return res;
    }
    LL exGCD(LL one,LL ano,LL &x,LL &y)
    {
        if(ano==0)    return (x=1,y=0,one);
        else
        {
            LL tmp=exGCD(ano,one%ano,y,x);
            y-=(one/ano)*x;
            return tmp;
        }
    }
    LL exCRT(LL n,LL one[],LL ano[])
    {
        LL x,y,res=one[1],M=ano[1];
        for(int i=2;i<=n;++i)
        {
            LL a=M,b=ano[i],c=(one[i]-res%b+b)%b,tmp=exGCD(a,b,x,y),d=b/tmp;
            if(c%tmp)    return -1;
            x=ftimes(x,c/tmp,d);
            res+=x*M,M*=d,res=(res%M+M)%M;
        }
        return (res%M+M)%M;
    }
};
int t;
LL one[10],ano[10],ans;
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        LL X,Y,P,Q;
        scanf("%lld %lld %lld %lld",&X,&Y,&P,&Q);
        ans=INF;
        for(LL i=X;i<X+Y;++i)
        {
            for(int j=P;j<P+Q;++j)
            {
                using namespace NumbTheo;
                one[1]=i,ano[1]=((X+Y)<<1),one[2]=j,ano[2]=P+Q;
                LL tmp=exCRT(2,one,ano);
                if(~tmp)    ans=min(ans,tmp);
            }
        }
        if(ans==INF)    printf("infinity\n");
        else    printf("%lld\n",ans);
    }
    return 0;
}

「ABC 193F」Zebraness

Link.

把 $i+j$ 为奇数的地方反转一下,然后连边求最小割。

#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
#define getID(x,y) (((x)-1)*n+(y))
namespace MaxFlow
{
    queue<int> q;
    const LL INF=1e9;
    int S,T,head[10010],Cur[10010],cntot=1,all,vis[10010];
    LL dep[10010];
    struct Edge
    {
        int to,nxt;
        LL c;
        Edge(int A=0,int B=0,LL C=0){to=A,nxt=B,c=C;}
    }as[500010];
    bool bfs()
    {
        for(int i=1;i<=all;++i)    vis[i]=0,dep[i]=INF;
        q.push(S),dep[S]=0,vis[S]=1;
        while(!q.empty())
        {
            int now=q.front();
            q.pop(),vis[now]=0;
            for(int i=head[now];i;i=as[i].nxt)
            {
                int y=as[i].to;
                LL c=as[i].c;
                if(c&&dep[y]>dep[now]+1)
                {
                    dep[y]=dep[now]+1;
                    if(!vis[y])    q.push(y),vis[y]=1;
                }
            }
        }
        return dep[T]<INF;
    }
    LL dfs(int x,LL lav)
    {
        if(x==T)    return lav;
        LL used=0;
        vis[x]=1;
        for(int &i=Cur[x];i;i=as[i].nxt)
        {
            int y=as[i].to;
            LL c=as[i].c;
            if(c&&dep[y]==dep[x]+1&&!vis[y])
            {
                LL tmp=dfs(y,min(lav-used,c));
                as[i].c-=tmp,as[i^1].c+=tmp,used+=tmp;
                if(lav==used)    break;
            }
        }
        if(used<lav)    dep[x]=INF;
        vis[x]=0;
        return used;
    }
    LL Dinic()
    {
        LL res=0;
        while(bfs())
        {
            for(int i=1;i<=all;++i)    vis[i]=0,Cur[i]=head[i];
            res+=dfs(S,INF);
        }
        return res;
    }
}using namespace MaxFlow;
int n;
int rop()
{
    char res=getchar();
    while((res^'B')&&(res^'W')&&(res^'?'))    res=getchar();
    if(res=='?')    return -1;
    else if(res=='B')    return 1;
    else    return 0;
}
void addEdge(int one,int ano,int lav)
{
    as[++cntot]=Edge(ano,head[one],lav);
    head[one]=cntot;
    as[++cntot]=Edge(one,head[ano],0);
    head[ano]=cntot;
}
int main()
{
    scanf("%d",&n),all=n*n;
    S=(++all),T=(++all);
    for(int i=1;i<=n;++i)
    {
        for(int j=1;j<=n;++j)
        {
            int x=rop();
            if(~x)
            {
                if((i+j)&1)    x^=1;
                if(x)    addEdge(S,getID(i,j),INF);
                else    addEdge(getID(i,j),T,INF);
            }
        }
    }
    for(int i=1;i<n;++i)
    {
        for(int j=1;j<=n;++j)    addEdge(getID(i,j),getID(i+1,j),1),addEdge(getID(i+1,j),getID(i,j),1);
    }
    for(int i=1;i<=n;++i)
    {
        for(int j=1;j<n;++j)    addEdge(getID(i,j),getID(i,j+1),1),addEdge(getID(i,j+1),getID(i,j),1);
    }
    printf("%lld\n",2*n*(n-1)-Dinic());
    return 0;
}