CF628F Bear and Fair Set

Limak 是一只可怕的大灰熊。有一天你穿行在森林中,非常不幸地,你碰到了 Limak——它会吃掉你的所有曲奇(然而那是你准备野餐的零食 QwQ)除非你充分向它展示出你的数学才能。为了考验你的数学能力,它给你出了一道难题。

众所周知,Limak 就像其他熊一样,拥有一个集合:

  1. 集合里的元素均为正整数且互不相同;
  2. 元素的个数为 \(n\)\(n\)\(5\) 的倍数;
  3. 元素的大小在 \(1\)\(b\) 之间(包括 \(1,b\));
  4. 集合中恰有 \(\frac n5\) 个数除以 \(5\)\(0\)\(\frac n5\) 个数除以 \(5\)\(1\) …… \(\frac n5\) 个数除以 \(5\)\(4\)

Limak 露出了狡黠的笑容(TAT)并给了你 \(q\) 个关于这个集合的提示,每个提示表示如下:

大小在 \(1\)\(u_i\) 的元素恰好有 \(t_i\)

于是你开始思考,突然你意识到有什么不对——Limak 是否在欺骗你?也就是说根本没有一个集合满足它的提示以及集合本身的要求?

如果存在至少一个集合满足条件,输出 "fair" 即 Limak 没有说谎;否则输出 "unfair" ,真是一只狡诈的灰熊!

\(4≤n≤b≤10^4\)\(n\)\(5\) 整除;\(1≤q≤10^4\)\(1≤u_i≤b\)\(0≤t_i≤ n\)


感觉这题用不着高深的网络流建模技巧,直接二分图匹配不好吗。

考虑 \(b\) 中每个数对每个余数匹配, \(i\to i\%5\) ,流量为 \(1\)

然后考虑对集合的限制,差分完之后可以得到每个区间恰好有几个数,设当前区间为 \([l,r]\) 建一个虚点 \(x\)\(S\to x\) ,流量为区间恰好的数的个数, \(x\to i(l\le i\le r)\) ,流量为 \(1\)

最后模数向 \(T\) 连流量为 \(\frac{n}{5}\) 的边。

我们还需要满足集合限制中的恰好,可以看作是一条边流量的上下界,直接跑有源有汇上下界可行流就行了。

跑的很快QAQ

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
const int N = 1e4;
const int inf = 1e9;
using namespace std;
struct qry
{
    int u,t;
}a[N + 5];
int n,b,q,idc,id1[N + 5],S,T,id2[10],t[N + 5],fl[N * 10 + 5];
namespace F
{
    const int N = 1e6;
    const long long inf = 2e18;
    struct edges
    {
        int to;
        long long cost;
    }edge[N * 2 + 5];
    int nxt[N * 2 + 5],head[N + 5],edge_cnt = 1,dis[N + 5],q[N + 5],cur[N + 5],S,T;
    void add_edge(int u,int v,long long w)
    {
        edge[++edge_cnt] = (edges){v,w};
        nxt[edge_cnt] = head[u];
        head[u] = edge_cnt;
    }
    void add(int u,int v,long long w)
    {
        add_edge(u,v,w);
        add_edge(v,u,0);
    }
    int bfs()
    {
        for (int i = 1;i <= idc;i++)
            cur[i] = head[i],dis[i] = 0;
        int l = 1,r = 0;
        dis[S] = 1;
        q[++r] = S;
        while (l <= r)
        {
            int u = q[l++];
            for (int i = head[u];i;i = nxt[i])
            {
                int v = edge[i].to,w = edge[i].cost;
                if (w && !dis[v])
                {
                    dis[v] = dis[u] + 1;
                    q[++r] = v;
                }
            }
        }
        return dis[T];
    }
    long long dfs(int u,long long flow)
    {
        if (u == T)
            return flow;
        long long sm = 0;
        for (int &i = cur[u];i;i = nxt[i])
        {
            int v = edge[i].to;
            long long w = edge[i].cost;
            if (dis[v] == dis[u] + 1 && w)
            {
                long long res = dfs(v,min(w,flow));
                edge[i].cost -= res;
                edge[i ^ 1].cost += res;
                sm += res;
                flow -= res;
                if (!flow)
                    break;
            }
        }
        return sm;
    }
    long long dinic(int s,int t)
    {
        S = s;T = t;
        long long ans = 0;
        while (bfs())
            ans += dfs(S,inf);
        return ans;
    }
    void clear()
    {
        edge_cnt = 1;
        for (int i = 1;i <= idc;i++)
            head[i] = 0;
        idc = 0;
    }
    bool check(int S,int T)
    {
        for (int i = head[S];i;i = nxt[i])
            if (edge[i].cost)
                return 0;
        for (int i = head[T];i;i = nxt[i])
            if (edge[i ^ 1].cost)
                return 0;
        return 1;
    }
}
bool cmp(qry a,qry b)
{
    return a.u < b.u;
}
int main()
{
    scanf("%d%d%d",&n,&b,&q);
    for (int i = 1;i <= q;i++)
        scanf("%d%d",&a[i].u,&a[i].t);
    S = ++idc;T = ++idc;
    for (int i = 1;i <= b;i++)
        id1[i] = ++idc;
    for (int i = 0;i <= 4;i++)
        id2[i] = ++idc;
    for (int i = 1;i <= b;i++)
        F::add(id1[i],id2[i % 5],1);
    sort(a + 1,a + q + 1,cmp);
    for (int i = 1;i <= q;i++)
    {
        if (!t[a[i].u])
            t[a[i].u] = a[i].t;
        else
        {
            if (t[a[i].u] != a[i].t)
            {
                cout<<"unfair"<<endl;
                return 0;
            }
        }
        if (a[i].u != a[i - 1].u)
        {
            int x = a[i].t - a[i - 1].t;
            if (x < 0)
            {
                cout<<"unfair"<<endl;
                return 0;
            }
            int nw = ++idc;
            F::add(S,nw,0);
            fl[S] -= x;
            fl[nw] += x;
            for (int j = a[i - 1].u + 1;j <= a[i].u;j++)
                F::add(nw,id1[j],1);
        }
    }
    for (int i = a[q].u + 1;i <= b;i++)
        F::add(S,id1[i],1);
    for (int i = 0;i <= 4;i++)
    {
        F::add(id2[i],T,0);
        fl[id2[i]] -= n / 5;
    }
    F::add(T,S,inf);
    fl[T] = n;
    int ss = ++idc,tt = ++idc;
    for (int i = 1;i <= idc;i++)
        if (fl[i] < 0)
            F::add(i,tt,-fl[i]);
        else
            if (fl[i] > 0)
                F::add(ss,i,fl[i]);
    int x = F::dinic(ss,tt);
    if (F::check(ss,tt))
        cout<<"fair"<<endl;
    else
        cout<<"unfair"<<endl;
    return 0;
}
posted @ 2021-03-21 17:47  eee_hoho  阅读(74)  评论(0编辑  收藏  举报