0118ACM autistic race

<Foreword>

ACM Race: vjudge 20200118acm Race

Take a note of what I had done.

That is decadent.

<Text>

<Exam experience>

Today acm race teammates easily found, the result is a lazy goods, do not write a few questions, hey.

He wrote one of the most water-E, then two is what I wrote, I quite want to call someone.

The title is simply a malignant tumor, it can not be described.

Address game

Password: nicaibudao


I would like to say playing teammates (zjh) allocated about problems. He picked up directly E title, burst cut a few minutes, the audience a blood, I was scared to death, but after the exam questions that most E water, a few lines of code.

I got a D title, looked a little down, as did the original title or the title, also finished a few minutes, is not a blood. Interval is not the minimum and maintain a monotonous stack and messing around on the line. Each trip back and forth to maintain the array, and then direct calculation.

Then the audience into a bottleneck, long time no one cut out of question except DE outside.

Then the first matter of beating and hanging fjz audience, I began to knock F title, after his teammates finished no E began (da) the (shui) things (te) thing (shui), they all went to dinner, and I knock in the engine room .

Has been 6:00 WA, I do not know why. Between despair added a long long he would really over. . (Turn the Tables)

Then take a look at each question time is also knock out mess. . . autistic

Finally only rank5, not instant noodles, but I did not eat two meals a ah ah ah ah ah ah ah ah ah ah ah ah ah ah.

At night, which is now beginning to prowl, the feeling did not eat, just write blog autistic go.

Very poor gaming experience, the whole being suspended or beaten. When it became the beginning of a long time rank1, because we all usually do not.

Proud posted a map (PS: No. teammates, named me no rain melon):


Part of the solution to a problem

A - Negative Cycle AtCoder - 5147

A title will not, copy a bit, at least write their own, looked like better understood.

\(\mathrm{Code:}\)

#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 - Robots and Exits - AtCoder - 4353

B title simply do not write, brush title record table casually write something on the line.

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打完,神清气爽,回头刷题。

Guess you like

Origin www.cnblogs.com/zqytcl/p/12210945.html