[atcoder arc107]解题报告

arc 的题目脑洞也太大了……
后面多补 arc 的题目涨涨姿势(
比赛链接


A Simple Math

这个式子其实很好算的嘛(
因为 $a,b,c$ 都是独立的,直接三个等差就完事了。
最后答案就是 $\frac{A(A+1)B(B+1)C(C+1)}{8}$.

#include <bits/stdc++.h>
#define ll long long
#define ls id << 1
#define rs id << 1 | 1
#define mem(array, value, size, type) memset(array, value, ((size) + 5) * sizeof(type))
#define memarray(array, value) memset(array, value, sizeof(array))
#define fillarray(array, value, begin, end) fill((array) + (begin), (array) + (end) + 1, value)
#define fillvector(v, value) fill((v).begin(), (v).end(), value)
#define pb(x) push_back(x)
#define st(x) (1LL << (x))
#define pii pair<int, int>
#define mp(a, b) make_pair((a), (b))
#define Flush fflush(stdout)
#define vecfirst (*vec.begin())
#define veclast (*vec.rbegin())
#define vecall(v) (v).begin(), (v).end()
#define vecupsort(v) (sort((v).begin(), (v).end()))
#define vecdownsort(v, type) (sort(vecall(v), greater<type>()))
#define veccmpsort(v, cmp) (sort(vecall(v), cmp))
using namespace std;
const int N = 500050;
const int inf = 0x3f3f3f3f;
const ll llinf = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const int MOD = 1e9 + 7;
const double PI = acos(-1.0);
clock_t TIME__START, TIME__END;
void program_end()
{
#ifdef ONLINE
    printf("\n\nTime used: %.6lf(s)\n", ((double)TIME__END - TIME__START) / 1000);
    system("pause");
#endif
}
ll mi(ll a, ll b)
{
    ll ret = 1;
    while (b)
    {
        if (b & 1)
            ret = ret * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ret;
}
ll A, B, C;
inline void solve()
{
    cin >> A >> B >> C;
    ll ans = A * (A + 1) % mod * B % mod * (B + 1) % mod * C % mod * (C + 1) % mod * mi(8, mod - 2) % mod;
    cout << ans << endl;
}
int main()
{
    TIME__START = clock();
    int Test = 1;
    // scanf("%d", &Test);
    while (Test--)
    {
        solve();
        // if (Test)
        //     putchar('\n');
    }
    TIME__END = clock();
    program_end();
    return 0;
}
B Quadruple

将式子移项,变成 $a+b=K+c+d$,那么显然我们只需要看 $a+b$ 和 $c+d$ 分别有多少对就可以了。
设 $c(k)$ 表示 $i+j=k,1\le i,j \le n$ 的 $(i,j)$ 对数。不难得出 $c(k) = \min(k-1,2n-k+1)$(你要用生成函数去推导我也不拦你……)
那么答案就是 $\sum\limits_{i=\max(2,k+2)}^{\min(2n,2n+k)}c(i)\cdot c(i+k)$.

#include <bits/stdc++.h>
#define ll long long
#define ls id << 1
#define rs id << 1 | 1
#define mem(array, value, size, type) memset(array, value, ((size) + 5) * sizeof(type))
#define memarray(array, value) memset(array, value, sizeof(array))
#define fillarray(array, value, begin, end) fill((array) + (begin), (array) + (end) + 1, value)
#define fillvector(v, value) fill((v).begin(), (v).end(), value)
#define pb(x) push_back(x)
#define st(x) (1LL << (x))
#define pii pair<int, int>
#define mp(a, b) make_pair((a), (b))
#define Flush fflush(stdout)
#define vecfirst (*vec.begin())
#define veclast (*vec.rbegin())
#define vecall(v) (v).begin(), (v).end()
#define vecupsort(v) (sort((v).begin(), (v).end()))
#define vecdownsort(v, type) (sort(vecall(v), greater<type>()))
#define veccmpsort(v, cmp) (sort(vecall(v), cmp))
using namespace std;
const int N = 500050;
const int inf = 0x3f3f3f3f;
const ll llinf = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const int MOD = 1e9 + 7;
const double PI = acos(-1.0);
clock_t TIME__START, TIME__END;
void program_end()
{
#ifdef ONLINE
    printf("\n\nTime used: %.6lf(s)\n", ((double)TIME__END - TIME__START) / 1000);
    system("pause");
#endif
}
int n, k;
ll c[N];
void initc()
{
    for (int i = 1; i <= 2 * n; ++i)
    {
        c[i] = min(i - 1, 2 * n - i + 1);
    }
}
inline void solve()
{
    ll ans = 0;
    scanf("%d%d", &n, &k);
    initc();
    for (int i = 2; i <= 2 * n; ++i)
        if (i > k + 1 && i - k <= 2 * n)
            ans += c[i] * c[i - k];
    cout << ans << endl;
}
int main()
{
    TIME__START = clock();
    int Test = 1;
    // scanf("%d", &Test);
    while (Test--)
    {
        solve();
        // if (Test)
        //     putchar('\n');
    }
    TIME__END = clock();
    program_end();
    return 0;
}
C Shuffle Permutation

首先来看一个结论:两个点之间可以交换的话,就给这两个点连一条边。$n$ 个点如果通过这些边连成一个连通块的话,那么他们可以构成任意排列,即排列数就是 $n!$。
那么这个题就很简单了:直接枚举每两行,看这两行是否可以交换,可以的话就将这两行的下标打进一个集合内,最后行的贡献就是每个集合的大小的阶乘之积。对于列也是相同的操作,最后答案就是行的贡献乘以列的贡献。
也就是说 $1\sim N^2$ 这个条件没有啥用其实(

#include <bits/stdc++.h>
#define ll long long
#define ls id << 1
#define rs id << 1 | 1
#define mem(array, value, size, type) memset(array, value, ((size) + 5) * sizeof(type))
#define memarray(array, value) memset(array, value, sizeof(array))
#define fillarray(array, value, begin, end) fill((array) + (begin), (array) + (end) + 1, value)
#define fillvector(v, value) fill((v).begin(), (v).end(), value)
#define pb(x) push_back(x)
#define st(x) (1LL << (x))
#define pii pair<int, int>
#define mp(a, b) make_pair((a), (b))
#define Flush fflush(stdout)
#define vecfirst (*vec.begin())
#define veclast (*vec.rbegin())
#define vecall(v) (v).begin(), (v).end()
#define vecupsort(v) (sort((v).begin(), (v).end()))
#define vecdownsort(v, type) (sort(vecall(v), greater<type>()))
#define veccmpsort(v, cmp) (sort(vecall(v), cmp))
using namespace std;
const int N = 55;
const int inf = 0x3f3f3f3f;
const ll llinf = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const int MOD = 1e9 + 7;
const double PI = acos(-1.0);
clock_t TIME__START, TIME__END;
void program_end()
{
#ifdef ONLINE
    printf("\n\nTime used: %.6lf(s)\n", ((double)TIME__END - TIME__START) / 1000);
    system("pause");
#endif
}
int n, k;
int a[N][N];
int f[2][N];
ll vis[2][N];
int Find(int id, int x) { return f[id][x] == x ? x : f[id][x] = Find(id, f[id][x]); }
ll ans = 1, fac[N];
void Union(int id, int x, int y)
{
    int fx = Find(id, x), fy = Find(id, y);
    if (fx != fy)
        f[id][fy] = fx;
}
inline void solve()
{
    cin >> n >> k;
    fac[0] = 1;
    for (int i = 1; i <= 50; ++i)
        fac[i] = fac[i - 1] * i % mod;
    for (int i = 1; i <= n; ++i)
        f[0][i] = f[1][i] = i;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            cin >> a[i][j];
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
        {
            bool flag = true;
            for (int p = 1; p <= n; ++p)
            {
                if (a[i][p] + a[j][p] > k)
                    flag = false;
            }
            if (flag)
                Union(0, i, j);
        }
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
        {
            bool flag = true;
            for (int p = 1; p <= n; ++p)
            {
                if (a[p][i] + a[p][j] > k)
                    flag = false;
            }
            if (flag)
                Union(1, i, j);
        }
    for (int i = 1; i <= n; ++i)
    {
        vis[0][Find(0, i)]++;
        vis[1][Find(1, i)]++;
    }
    for (int i = 1; i <= n; ++i)
    {
        int f0 = Find(0, i), f1 = Find(1, i);
        if (vis[0][f0] != -1)
        {
            ans *= fac[vis[0][f0]];
            ans %= mod;
            vis[0][f0] = -1;
        }
        if (vis[1][f1] != -1)
        {
            ans *= fac[vis[1][f1]];
            ans %= mod;
            vis[1][f1] = -1;
        }
    }
    cout << ans << endl;
}
int main()
{
    TIME__START = clock();
    int Test = 1;
    // scanf("%d", &Test);
    while (Test--)
    {
        solve();
        // if (Test)
        //     putchar('\n');
    }
    TIME__END = clock();
    program_end();
    return 0;
}
D Number of Multisets

设 $dp(n,k)$ 表示要用 $n$ 个数去构成和为 $k$ 的集合个数。这里的转移其实脑洞很大……

  1. 如果当前放一个 $1$ 的话,那么问题就变成了 $n-1$ 个数去构成和为 $k-1$ 的集合个数,那么 $dp(n,k)+=dp(n-1,k-1)$;
  2. 如果当前不放 $1$ 的话,那么我们还是剩 $n$ 个数要去填,但是不准用 $1$。这个时候如果我们将后面的数乘以 $2$,那么问题就变成用 $n$ 个数组成和为 $2k$ 的集合个数。注意到这个时候又可以用 $1$ 了,因为这个 $1$ 是由 $\frac{1}{2}$ 来的,所以就有 $dp(n,k)+=dp(n,2k)$。

注意到第二个操作实际上不会很大($\log n$ 的),所以总的时间复杂度不会很大。

#include <bits/stdc++.h>
#define ll long long
#define ls id << 1
#define rs id << 1 | 1
#define mem(array, value, size, type) memset(array, value, ((size) + 5) * sizeof(type))
#define memarray(array, value) memset(array, value, sizeof(array))
#define fillarray(array, value, begin, end) fill((array) + (begin), (array) + (end) + 1, value)
#define fillvector(v, value) fill((v).begin(), (v).end(), value)
#define pb(x) push_back(x)
#define st(x) (1LL << (x))
#define pii pair<int, int>
#define mp(a, b) make_pair((a), (b))
#define Flush fflush(stdout)
#define vecfirst (*vec.begin())
#define veclast (*vec.rbegin())
#define vecall(v) (v).begin(), (v).end()
#define vecupsort(v) (sort((v).begin(), (v).end()))
#define vecdownsort(v, type) (sort(vecall(v), greater<type>()))
#define veccmpsort(v, cmp) (sort(vecall(v), cmp))
using namespace std;
const int N = 3050;
const int inf = 0x3f3f3f3f;
const ll llinf = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const int MOD = 1e9 + 7;
const double PI = acos(-1.0);
clock_t TIME__START, TIME__END;
void program_end()
{
#ifdef ONLINE
    printf("\n\nTime used: %.6lf(s)\n", ((double)TIME__END - TIME__START) / 1000);
    system("pause");
#endif
}
ll dp[N][N];
ll dfs(int n, int k)
{
    if (n <= k)
        return (n == k);
    if (n == 0 && k == 0)
        return 1;
    if (k == 0)
        return 0;
    if (~dp[n][k])
        return dp[n][k];
    ll &ret = dp[n][k];
    ret = 0;
    ret += dfs(n - 1, k - 1);
    ret += dfs(n, 2 * k);
    ret %= mod;
    return ret;
}
inline void solve()
{
    memarray(dp, -1);
    int n, k;
    scanf("%d%d", &n, &k);
    ll ans = dfs(n, k);
    cout << ans << '\n';
}
int main()
{
    TIME__START = clock();
    int Test = 1;
    // scanf("%d", &Test);
    while (Test--)
    {
        solve();
        // if (Test)
        //     putchar('\n');
    }
    TIME__END = clock();
    program_end();
    return 0;
}
E Mex Mat

通过打表可以发现,当 $n\ge 5$ 的时候,有一个绝妙的性质:$a(i,j)=a(i-1,j-1)$,然后直接根据这个东西来做就行……
怎么证明我还不太会(

#include <bits/stdc++.h>
#define ll long long
#define ls id << 1
#define rs id << 1 | 1
#define mem(array, value, size, type) memset(array, value, ((size) + 5) * sizeof(type))
#define memarray(array, value) memset(array, value, sizeof(array))
#define fillarray(array, value, begin, end) fill((array) + (begin), (array) + (end) + 1, value)
#define fillvector(v, value) fill((v).begin(), (v).end(), value)
#define pb(x) push_back(x)
#define st(x) (1LL << (x))
#define pii pair<int, int>
#define mp(a, b) make_pair((a), (b))
#define Flush fflush(stdout)
#define vecfirst (*vec.begin())
#define veclast (*vec.rbegin())
#define vecall(v) (v).begin(), (v).end()
#define vecupsort(v) (sort((v).begin(), (v).end()))
#define vecdownsort(v, type) (sort(vecall(v), greater<type>()))
#define veccmpsort(v, cmp) (sort(vecall(v), cmp))
using namespace std;
const int N = 500050;
const int inf = 0x3f3f3f3f;
const ll llinf = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const int MOD = 1e9 + 7;
const double PI = acos(-1.0);
clock_t TIME__START, TIME__END;
void program_end()
{
#ifdef ONLINE
    printf("\n\nTime used: %.6lf(s)\n", ((double)TIME__END - TIME__START) / 1000);
    system("pause");
#endif
}
int n;
inline int mex(int a, int b)
{
    int vis[3] = {0};
    vis[a] = vis[b] = 1;
    for (int i = 0; i < 3; ++i)
        if (!vis[i])
            return i;
    return -1;
}
vector<int> a[N];
ll ans[5];
void solve6()
{
    int a[10][10];
    memarray(a, 0);
    for (int i = 1; i <= n; ++i)
        scanf("%d", &a[1][i]);
    for (int i = 2; i <= n; ++i)
        scanf("%d", &a[i][1]);
    for (int i = 2; i <= n; ++i)
        for (int j = 2; j <= n; ++j)
            a[i][j] = mex(a[i - 1][j], a[i][j - 1]);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            ans[a[i][j]]++;
    for (int i = 0; i < 3; ++i)
        printf("%lld ", ans[i]);
}
inline void solve()
{
    scanf("%d", &n);
    if (n <= 6)
        return solve6(), void();
    for (int i = 1; i <= 5; ++i)
        a[i].resize(n + 5), a[i][0] = 0;
    for (int i = 1; i <= n; ++i)
        scanf("%d", &a[1][i]), ans[a[1][i]]++;
    for (int i = 2; i <= n; ++i)
    {
        if (i > 5)
            a[i].resize(6);
        scanf("%d", &a[i][1]);
        ans[a[i][1]]++;
        a[i][0] = 0;
    }
    for (int i = 2; i <= 5; ++i)
        for (int j = 2; j <= n; ++j)
            a[i][j] = mex(a[i - 1][j], a[i][j - 1]), ans[a[i][j]]++;
    for (int i = 6; i <= n; ++i)
        for (int j = 2; j <= 5; ++j)
            a[i][j] = mex(a[i - 1][j], a[i][j - 1]), ans[a[i][j]]++;
    for (int j = 5; j <= n; ++j)
    {
        int x = a[5][j];
        ans[x] += min(n - 5, n - j);
    }
    for (int i = 6; i <= n; ++i)
    {
        int x = a[i][5];
        ans[x] += min(n - i, n - 5);
    }
    for (int i = 0; i < 3; ++i)
        printf("%lld ", ans[i]);
}
int main()
{
    TIME__START = clock();
    int Test = 1;
    // scanf("%d", &Test);
    while (Test--)
    {
        solve();
        // if (Test)
        //     putchar('\n');
    }
    TIME__END = clock();
    program_end();
    return 0;
}
F Sum of Abs

题解先留着,等脑子清醒了好好捋捋这个题,特别巧妙

#include <bits/stdc++.h>
#define ll long long
#define ls id << 1
#define rs id << 1 | 1
#define mem(array, value, size, type) memset(array, value, ((size) + 5) * sizeof(type))
#define memarray(array, value) memset(array, value, sizeof(array))
#define fillarray(array, value, begin, end) fill((array) + (begin), (array) + (end) + 1, value)
#define fillvector(v, value) fill((v).begin(), (v).end(), value)
#define pb(x) push_back(x)
#define st(x) (1LL << (x))
#define pii pair<int, int>
#define mp(a, b) make_pair((a), (b))
#define Flush fflush(stdout)
#define vecfirst (*vec.begin())
#define veclast (*vec.rbegin())
#define vecall(v) (v).begin(), (v).end()
#define vecupsort(v) (sort((v).begin(), (v).end()))
#define vecdownsort(v, type) (sort(vecall(v), greater<type>()))
#define veccmpsort(v, cmp) (sort(vecall(v), cmp))
using namespace std;
const int N = 500050;
const int inf = 0x3f3f3f3f;
const ll llinf = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const int MOD = 1e9 + 7;
const double PI = acos(-1.0);
clock_t TIME__START, TIME__END;
void program_end()
{
#ifdef ONLINE
    printf("\n\nTime used: %.6lf(s)\n", ((double)TIME__END - TIME__START) / 1000);
    system("pause");
#endif
}
const int MAXN = 1000, MAXM = N;
struct ISAP
{
    struct Edge
    {
        ll v, w, nxt;
    } edge[MAXM];
    ll tot, num, s, t, n;
    ll head[MAXN];
    void init()
    {
        memset(head, -1, sizeof(head));
        tot = 0;
    }
    void add_Edge(ll u, ll v, ll w)
    {
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].nxt = head[u];
        head[u] = tot++;
        edge[tot].v = u;
        edge[tot].w = 0;
        edge[tot].nxt = head[v];
        head[v] = tot++;
    }
    ll d[MAXN], vis[MAXN], gap[MAXN];
    void bfs()
    {
        memset(d, 0, (n + 5) * sizeof(ll));
        memset(gap, 0, (n + 5) * sizeof(ll));
        memset(vis, 0, (n + 5) * sizeof(ll));
        queue<int> q;
        q.push(t);
        vis[t] = 1;
        while (!q.empty())
        {
            int u = q.front();
            q.pop();
            for (int i = head[u]; ~i; i = edge[i].nxt)
            {
                int v = edge[i].v;
                if (!vis[v])
                {
                    d[v] = d[u] + 1;
                    gap[d[v]]++;
                    q.push(v);
                    vis[v] = 1;
                }
            }
        }
    }
    ll last[MAXN];
    ll dfs(int u, ll f)
    {
        if (u == t)
            return f;
        ll sap = 0;
        for (int i = last[u]; ~i; i = edge[i].nxt)
        {
            int v = edge[i].v;
            if (edge[i].w > 0 && d[u] == d[v] + 1)
            {
                last[u] = i;
                ll tmp = dfs(v, min(f - sap, edge[i].w));
                edge[i].w -= tmp;
                edge[i ^ 1].w += tmp;
                sap += tmp;
                if (sap == f)
                    return sap;
            }
        }
        if (d[s] >= num)
            return sap;
        if (!(--gap[d[u]]))
            d[s] = num;
        ++gap[++d[u]];
        last[u] = head[u];
        return sap;
    }
    ll solve(int st, int ed, int n)
    {
        ll flow = 0;
        num = n;
        s = st;
        t = ed;
        bfs();
        memcpy(last, head, sizeof(head));
        while (d[s] < num)
            flow += dfs(s, inf);
        return flow;
    }
} G;
int n, m, S, T;
int a[350], b[350];
void add_node(int u)
{
    if (b[u] <= 0)
    {
        G.add_Edge(S, u, 0);
        G.add_Edge(u + n, T, -2 * b[u]);
        G.add_Edge(u, u + n, a[u] - b[u]);
    }
    else
    {
        G.add_Edge(S, u, 2 * b[u]);
        G.add_Edge(u + n, T, 0);
        G.add_Edge(u, u + n, a[u] + b[u]);
    }
}
inline void solve()
{
    G.init();
    scanf("%d%d", &n, &m);
    S = 2 * n + 3, T = 2 * n + 4;
    ll ans = 0;
    for (int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    for (int i = 1; i <= n; ++i)
        scanf("%d", &b[i]), ans += abs(b[i]);
    for (int i = 1; i <= m; ++i)
    {
        int u, v;
        scanf("%d%d", &u, &v);
        G.add_Edge(v + n, u, inf);
        G.add_Edge(u + n, v, inf);
    }
    for (int i = 1; i <= n; ++i)
        add_node(i);
    ans -= G.solve(S, T, 2 * n + 5);
    printf("%lld\n", ans);
}
int main()
{
    TIME__START = clock();
    int Test = 1;
    // scanf("%d", &Test);
    while (Test--)
    {
        solve();
        // if (Test)
        //     putchar('\n');
    }
    TIME__END = clock();
    program_end();
    return 0;
}

 

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注