0118ACM自閉症レース

<巻頭言>

ACM人種:vjudgeの20200118acm人種

私が行っていたものをメモします。

それは退廃的です。

<テキスト>

<受験経験>

今日ACMレースチームメイトを簡単に見つけ、結果は怠惰な商品です、ちょっと、いくつかの質問を書いていません。

彼は、私は非常に人を呼びたい、2つは、私が書いたもので、ほとんどの水-Eの1を書きました。

タイトルはそれを説明することができない、単に悪性腫瘍です。

住所ゲーム

パスワード:nicaibudao


私は問題について割り当てられたチームメイト(zjh)を再生言いたいです。彼は、数分をカットバースト直接Eのタイトルを拾った、血が、私は死におびえた観客が、試験問題の後、ほとんどのE水、数行のコード。

私は、Dのタイトルを得たオリジナルのタイトルやタイトルは、また数分を終えたよう、少し下を見て、血液ではありません。間隔は最小ではなく、単調なスタックを維持し、ライン上いじり。各旅行の前後には、アレイ、その後、直接計算を維持します。

そして、ボトルネックに観客、長時間DEの外を除いて、質問のうち誰カット。

彼のチームメイトは何のEは、(DA)(風水)のもの(TE)の事(風水)始まっていない、彼らはすべての夕食に行き、私はエンジンルーム内にノック終了後叩打の最初の問題とぶら下がっfjz観客は、私は、Fのタイトルをノックし始めました。

午前6時WAされてきた、私は理由を知りません。絶望の間に長い長い彼は本当にオーバーだろう追加。(表を回します)

その後も混乱をノックアウトされた各質問の時間を見てみましょう。自閉症

最後にだけでなく、インスタントラーメン、rank5が、私は2食を食べていませんでしたああああああああああああああああああああああああああああ。

今徘徊し始めている夜、で、気持ちだけ書き込み自閉症行くブログ、食べませんでした。

非常に悪いゲーム体験は、全存在が中断または殴ら。それは、長い時間のランク-1の始まりになったとき、私たちはすべて、通常はしませんので。

プラウドマップを掲載(PS:第チームメイト、雨メロン私の名前ません):


この問題に対する解決策の一部

-負のサイクルの AtCoder - 5147

タイトルは、少なくとも、ビットをコピーして、より良い理解のように見え、自分自身を書きません。

\(\ mathrm {コード:} \)

#include <bits/stdc++.h>
#define N      510
#define int    long long
using namespace std;
int a[N][N] = {};
int read()
{
    int  s = 0, w = 1;
    char c = getchar();
    while ((c < '0' || c > '9') && c != '-')
        c = getchar();
    if (c == '-')
        c = getchar(), w = -1;
    while (c <= '9' && c >= '0')
        s = (s << 3) + (s << 1) + c - '0', c = getchar();
    return s * w;
}
int n;
int b[N][N] = {}, c[N][N] = {};
int f[N][N] = {};
signed main()
{
    n = read();
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            if (i != j)
                a[i][j] = read();
    for (int i = 1; i <= n; ++i)
        for (int j = n; j >= i + 1; --j)
        {
            b[i][j] = b[i][j + 1];
            for (int k = 1; k <= i; ++k)
                b[i][j] += a[j][k];
        }
    for (int i = 1; i <= n; ++i)
        for (int j = i + 1; j <= n + 1; ++j)
        {
            c[i][j] = c[i][j - 1];
            for (int k = i; k <= j - 1; ++k)
                c[i][j] += a[k][j];
        }
    memset(f, 0x3f, sizeof(f));
    f[0][0] = 0;
    for (int i = 0; i <= n; ++i)
        for (int j = i; j <= n; ++j)
            if (f[i][j] < 1e18)
                for (int k = j + 1; k <= n + 1; ++k)
                    f[j][k] = min(f[j][k], f[i][j] + c[j + 1][k] + b[j][k + 1] - b[i][k + 1]);
    int minn = 1e18;
    for (int i = 0; i <= n; ++i)
        minn = min(minn, f[i][n + 1]);
    printf("%lld\n", minn);
    return 0;
}

B -ロボットと脱出 - AtCoder - 4353

Bのタイトルは、単に行にない書き込み、ブラシタイトルレコードテーブル気軽に書き込み何かをします。

C - 和風いろはちゃん / Iroha and Haiku - AtCoder - 1975

C题同。

D - Minimum Sum - AtCoder - 2060

稍微讲一下D,这题就是求每段子区间的最小值和。

每段考虑并不好做,考虑计算每个值的贡献。

一个位于\(i\)处的值\(x\)能影响到的区间一定是以它为最小值的区间,我们只需找到左右第一个比它小的值位置,这两个位置之间的区间都是以\(x\)为最小值得区间,计算个数以及贡献即可。

\[ \begin{aligned} & \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \sum_{1\leq l \leq r \leq n} min(a_l,a_{l+1}……a_{r-1},a_r)\\ &= \sum_{min(a_l,a_{l+1}……a_{r-1},a_r)=x} (r-i+1)\times (i-l+1) \times x \end{aligned} \]

两个单调栈一开,维护左/右比x小的第一个数位置,就分别是l、r了。

\(\mathrm{Code:}\)

#include <bits/stdc++.h>
#define N      200010
#define int    long long
using namespace std;
int n;
int a[N] = {};
int read()
{
    int  s = 0, w = 1;
    char c = getchar();
    while ((c < '0' || c > '9') && c != '-')
        c = getchar();
    if (c == '-')
        w = -1, c = getchar();
    while (c <= '9' && c >= '0')
        s = (s << 3) + (s << 1) + c - '0', c = getchar();
    return s * w;
}
int pre[N] = {}, suf[N] = {};
int q[N << 1] = {}, h = 1, t = 0;
void push1(int x)
{
    while (h <= t && a[q[t]] >= a[x])
        suf[q[t]] = x - 1, --t;
    q[++t] = x;
}
void push2(int x)
{
    while (h <= t && a[q[t]] >= a[x])
        pre[q[t]] = x + 1, --t;
    q[++t] = x;
}
signed main()
{
    n = read();
    for (int i = 1; i <= n; ++i)
        a[i] = read(), pre[i] = 1, suf[i] = n;
    for (int i = 1; i <= n; ++i)
        push1(i);
    h = 1; t = 0;
    for (int i = n; i >= 1; --i)
        push2(i);
    int sum = 0;
    for (int i = 1; i <= n; ++i)
    {
        sum += (i - pre[i] + 1) * (suf[i] - i + 1) * a[i];
    }
    printf("%lld\n", sum);
    return 0;
}

挺水一题,不知为何被拖了很久,没拿到一血。

E - STring - AtCoder - 2059

题目给一个巨tm大的操作次数(\(10^{10000}\))就是告诉你随便删就好了,管够。

所以E作为本场最水被过了。

zjh的\(\mathrm{Code:}\)

#include <bits/stdc++.h>
using namespace std ;
inline int read ()
{
    char c = getchar () ; int x = 0 , f = 1 ;
    while (c < '0' || c > '9') { if (c == '-') f = -1 ; c = getchar () ; }
    while (c >= '0' && c <= '9'){ x = x * 10 + c - '0' ; c = getchar () ; }
    return x * f ;
}
string s ;
int st[200005] , ans , top ;
int main ()
{
    cin >> s ;
    ans = s.size () ;
    for (int i = 0 ; i < s.size () ; i ++)
    {
        if (s[i] == 'S') st[++ top] = 'S' ;
        else if (top) top -- , ans -= 2 ;
    }
    cout << ans ;
}

F - Pizza Delivery - Gym - 101986F

这题也是我写的。

一直被long long 卡,要是开了long long 我午饭时间后的第二发就可以A,能吃上一顿饭呢。(但是晚上吃到泡面还是挺赚的)

之前我的分类讨论中,一开始我就分了最短路边和非最短路边,两者又进行了细分,后来发现不必要,对于非最短路边,直接判断就好。

最短路边略麻烦。

你要确定删去之后会不会对最短路径有影响,就要判断该边是否是属于最短路的边(注意最短路可能有多条)组成的图的割边了。

若不是桥,说明会有其他路径代替本路径,取反这条边没啥卵用。

若是桥,则它取反之后无法找到更短或相等的路径代替,是可以证明的,但是我不会。

那么局势变得明朗起来:

  • 找最短路,标记所有最短路上的边。
  • 在最短路径组成的图中找割边,可用两种方式实现。

对于最短路边,若是割边则翻转会产生影响。不是割边则不会。

对于非最短路边,强行把它放在最短路上看看和原最短路比起来怎么样。

割边的两种查找方式:重新建图tarjan,最短路路径计数。

贴出计数法判割边的代码:

\(\mathrm{Code:}\)

#include <bits/stdc++.h>
#define N      200010
#define int    long long
#define inf    0x3f3f3f3f
#define mp(x, y)    make_pair(x, y)
using namespace std;
int n, m;
struct gragh
{
    int to[N] = {}, net[N] = {}, w[N] = {};
    int from[N] = {};
    int fl[N] = {}, len = 0;
    inline void inc(int x, int y, int z)
    {
        to[++len] = y;
        from[len] = x;
        w[len]    = z;
        net[len]  = fl[x];
        fl[x]     = len;
    }
} G[2];
struct tree
{
    int to[N << 1] = {}, net[N] = {}, w[N] = {};
    int fl[N] = {}, len = 0;
    inline void inc(int x, int y, int z)
    {
        to[++len] = y;
        w[len]    = z;
        net[len]  = fl[x];
        fl[x]     = len;
    }
} T;
int read()
{
    int  s = 0, w = 1;
    char c = getchar();
    while ((c < '0' || c > '9') && c != '-')
        c = getchar();
    if (c == '-')
        c = getchar(), w = -1;
    while (c <= '9' && c >= '0')
        s = (s << 3) + (s << 1) + c - '0', c = getchar();
    return s * w;
}
int vis[N] = {}, dis[2][N] = {};
int is[2][N] = {}, si[2][N] = {};
void DJ(int st, int p)
{
    memset(dis[p], 0x3f, sizeof(dis[p]));
    memset(vis, 0, sizeof(vis));
    memset(is[p], 0, sizeof(is[p]));
    dis[p][st] = 0;
    si[p][st]  = 1;
    priority_queue<pair<int, int> >q;
    q.push(mp(0, st));
    while (!q.empty())
    {
        int t = q.top().second;
        q.pop();
        if (vis[t])
            continue;
        vis[t] = 1;
        for (int i = G[p].fl[t]; i; i = G[p].net[i])
        {
            int v = G[p].to[i];
            if (dis[p][v] > dis[p][t] + G[p].w[i])
            {
                dis[p][v] = dis[p][t] + G[p].w[i];
                si[p][v]  = si[p][t];
                q.push(mp(-dis[p][v], v));
            }
            else if (dis[p][v] == dis[p][t] + G[p].w[i])
                si[p][v] += si[p][t], si[p][v] %= inf;
        }
    }
}
signed main()
{
    n = read();
    m = read();
    for (int i = 1; i <= m; ++i)
    {
        int x = read(), y = read(), z = read();
        G[0].inc(x, y, z);
        G[1].inc(y, x, z);
    }
    DJ(1, 0);
    DJ(2, 1);
    int vis[N] = {};
    for (int i = 1; i <= G[0].len; ++i)
        if (dis[0][G[0].from[i]] + G[0].w[i] + dis[1][G[0].to[i]] == dis[0][2])
            is[0][i] = 1, 
            vis[G[0].from[i]] = vis[G[0].to[i]] = 1;
    for (int i = 1; i <= G[0].len; ++i)
    {
        if (is[0][i])
        {
            int u = G[0].from[i], v = G[0].to[i];
            if (si[0][u] * si[1][v] % inf == si[0][2])
            {
                puts("SAD");
            }
            else
            {
                puts("SOSO");
            }
        }
        else
        {
            int u = G[0].from[i], v = G[0].to[i];
            int minn = dis[0][v] + G[0].w[i] + dis[1][u];
            if (minn < dis[0][2])
                puts("HAPPY");
            else
                puts("SOSO");
        }
    }
    return 0;
}

G - New Year and Old Subsequence - CodeForces - 750E

毒瘤题。线段树优化广义矩乘,其实就是加速dp的递推。

我们将几种状态进行编号:\(\emptyset,2,20,201,2017\)分别编号01234.

这样对于每一个递推,就有一种编号间的递推转移了。

重定义乘法为dp的递推,在本题中为加法变取min,乘法变加法。

考虑构造转移矩阵。

对于当前字符为'2'时:若要保持空集,则需删去,代价为1,若不变成空集,则可以不花费代价。其他每个状态保持都无需花费,故转移为:

\[ \mathrm{ \begin{bmatrix} 0&1&inf&inf&inf\\ inf&0&inf&inf&inf\\ inf&inf&0&inf&inf\\ inf&inf&inf&0&inf\\ inf&inf&inf&inf&0 \end{bmatrix} } \]
其他字符类似。

对于字符'6',因为无论如何不能要它,所以从\(201、2017\)的转移保持代价为1,因为题目为子序列,所以2017这种状态也不能加6

\[ \begin{bmatrix} 0&inf&inf&inf&inf\\ inf&0&inf&inf&inf\\ inf&inf&0&inf&inf\\ inf&inf&inf&1&inf\\ inf&inf&inf&inf&1 \end{bmatrix} \]

用线段树维护运算,注意左右子矩阵顺序,即使这题中没问题,但是其他的广义运算是要注意的。

代码:

\(\mathrm{Code:}\)

#include <bits/stdc++.h>
#define int    long long
#define N      200010
using namespace std;
int n, m;
struct matrix
{
    int a[5][5];
    int n, m;
    matrix()
    {
        n = m = 0;
        memset(a, 0x3f, sizeof(a));
    }
    inline int *operator [](int x)
    {
        return a[x];
    }
    matrix operator *(matrix b)
    {
        matrix c;
        c.n = n; c.m = b.m;
        for (int i = 0; i < c.n; ++i)
            for (int j = 0; j < c.m; ++j)
                for (int k = 0; k < m; ++k)
                    c.a[i][j] = min(c.a[i][j], a[i][k] + b.a[k][j]);
        return c;
    }
};
struct segment_tree
{
    int    l, r;
    matrix k;
} tr[N << 2];
int read()
{
    int  s = 0, w = 1;
    char c = getchar();
    while ((c < '0' || c > '9') && c != '-')
        c = getchar();
    if (c == '-')
        w = -1, c = getchar();
    while (c <= '9' && c >= '0')
        s = (s << 3) + (s << 1) + c - '0', c = getchar();
    return s * w;
}
char s[N] = {};
inline void push(int p)
{
    tr[p].k = tr[p << 1].k * tr[p << 1 | 1].k;
}
void build(int p, int l, int r)
{
    tr[p].l = l; tr[p].r = r;
    if (l == r)
    {
        tr[p].k.n = tr[p].k.m = 5;
        for (int i = 0; i < 5; ++i)
            tr[p].k[i][i] = 0;
        if (s[l] == '2')
            tr[p].k[0][0] = 1, tr[p].k[0][1] = 0;
        if (s[l] == '0')
            tr[p].k[1][1] = 1, tr[p].k[1][2] = 0;
        if (s[l] == '1')
            tr[p].k[2][2] = 1, tr[p].k[2][3] = 0;
        if (s[l] == '7')
            tr[p].k[3][3] = 1, tr[p].k[3][4] = 0;
        if (s[l] == '6')
            tr[p].k[3][3] = 1, tr[p].k[4][4] = 1;
        return;
    }
    int mid = (l + r) >> 1;
    build(p << 1, l, mid);
    build(p << 1 | 1, mid + 1, r);
    push(p);
}
matrix ask(int p, int l, int r)
{
    if (l <= tr[p].l && tr[p].r <= r)
        return tr[p].k;
    int mid = (tr[p].l + tr[p].r) >> 1;
    if (r <= mid)
        return ask(p << 1, l, r);
    if (l > mid)
        return ask(p << 1 | 1, l, r);
    return ask(p << 1, l, r) * ask(p << 1 | 1, l, r);
}
signed main()
{
    n = read();
    m = read();
    cin >> (s + 1);
    build(1, 1, n);
    for (int i = 1; i <= m; ++i)
    {
        int    x = read(), y = read();
        matrix ans = ask(1, x, y);
        printf("%lld\n", ans[0][4] > n ? -1 : ans[0][4]);
    }
    return 0;
}

H - Shorten Diameter - AtCoder - 1981

没搞,听说第二水,也不想写了。

<后记>

然后就是这样了,一场ACM打完,神清气爽,回头刷题。

おすすめ

転載: www.cnblogs.com/zqytcl/p/12210945.html