其他分享
首页 > 其他分享> > CF #800 div 2

CF #800 div 2

作者:互联网

别问我为什么写简体了,问的话就换成繁体

A. Creep

贪心,\(01\) 交替放。

点击查看代码
#include <cstdio>
#include <cstring>
#include <cctype>
#include <iostream>
#include <sstream>
#include <stack>
#include <cmath>
#include <algorithm>
#include <map>
#include <queue>
#include <list>
#include <set>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;

const int maxn = 8e4 + 10, maxe = 8e4 + 10, maxt = maxn * 600;

int read()
{
    int x = 0;
    char c;
    bool f = 0;
    while (!isdigit(c = getchar()))
    {
        if (c == '-')
        {
            f = 1;
        }
    }
    do
    {
        x = (x << 1) + (x << 3) + (c ^ 48);
    } while (isdigit(c = getchar()));
    if (f)
    {
        return -x;
    }
    return x;
}

char getFunc()
{
    char c;
    while (!isalpha(c = getchar()))
    {
    }
    return c;
}

int main()
{
    int T = read();
    while (T--)
    {
        int a = read(), b = read();
        if (a >= b)
        {
            while (b)
            {
                --a;
                --b;
                putchar('0');
                putchar('1');
            }
            while (a)
            {
                --a;
                putchar('0');
            }
        }
        else
        {
            while (a)
            {
                --a;
                --b;
                putchar('1');
                putchar('0');
            }
            while (b)
            {
                --b;
                putchar('1');
            }
        }
        putchar('\n');
    }
}

B. Paranoid String

可以发现:

\(0000000001\)

\(1111111110\)

都很容易消掉。

然后如果一个串的末尾是 \(01\)

比如 \(100100001\)

发现都可以消成 \(000000001\) 的形式。

如果末尾是 \(10\)

都可以消成 \(11111110\) 的形式。

末尾是 \(00\) \(11\) 就不行了。

这样我们就知道只要一个串的末尾是 \(01\) 或 \(10\) 就能消掉。

串长为 \(1\) 单独另处理就行。

点击查看代码
#include <cstdio>
#include <cstring>
#include <cctype>
#include <iostream>
#include <sstream>
#include <stack>
#include <cmath>
#include <algorithm>
#include <map>
#include <queue>
#include <list>
#include <set>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;

const int maxn = 2e5 + 10, maxe = 8e4 + 10, maxt = maxn * 600;

int read()
{
    int x = 0;
    char c;
    bool f = 0;
    while (!isdigit(c = getchar()))
    {
        if (c == '-')
        {
            f = 1;
        }
    }
    do
    {
        x = (x << 1) + (x << 3) + (c ^ 48);
    } while (isdigit(c = getchar()));
    if (f)
    {
        return -x;
    }
    return x;
}

char getFunc()
{
    char c;
    while (!isalpha(c = getchar()))
    {
    }
    return c;
}

char str[maxn];

int main()
{
    int T = read();
    while (T--)
    {
        int n = read();
        scanf("%s", str);
        ll ans = n;
        for (int i = 1; i < n; ++i)
        {
            if (((str[i - 1] - '0') ^ (str[i] - '0')) == 1)
            {
                ans += i;
            }
        }
        printf("%lld\n", ans);
    }
}

C. Directional Increase

简单分析可以看出:

每次要让一个位置加一,就需要从它往右移,而且他右边的某个位置还得减一。

如果要让一个位置减一,就需要从它往左移,并且它左边的一个位置还得加一。

这样我们得出如果所有数的和不为零则显然无解。

要在第一个位置加数字,要保证进和出第一个位置的次数都等于需要在这个位置上加的数字。并且因为第一个位置不能左移,所以第一个位置上的数不能减,所以必须要保证第一个位置上的数大于零。

我们可以发现如果把第一个位置上需要累加的数都放到第二个位置上面,这时候第二个位置及其后面的数构成的新问题与原问题是等价的。

比如我第一个数要加 2,那么我可以右移再左移再右移再左移,这样第一个数加了 2,第二个数减了 2,就需要多加一个 2,处理第二个数的过程可以插在几次左右移中间。

因此可以求下前缀和,每次前缀和 > 0 说明可以转化成新问题,< 0 说明无解,如果前缀和 = 0 就说明此时必须待在原位置保持不动,若前缀和后面还有不为 0 的数就判无解。

点击查看代码
#include <cstdio>
#include <cstring>
#include <cctype>
#include <iostream>
#include <sstream>
#include <stack>
#include <cmath>
#include <algorithm>
#include <map>
#include <queue>
#include <list>
#include <set>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;

const int maxn = 2e5 + 10, maxe = 8e4 + 10, maxt = maxn * 600;

int read()
{
    int x = 0;
    char c;
    bool f = 0;
    while (!isdigit(c = getchar()))
    {
        if (c == '-')
        {
            f = 1;
        }
    }
    do
    {
        x = (x << 1) + (x << 3) + (c ^ 48);
    } while (isdigit(c = getchar()));
    if (f)
    {
        return -x;
    }
    return x;
}

char getFunc()
{
    char c;
    while (!isalpha(c = getchar()))
    {
    }
    return c;
}

int num[maxn];
int n;

bool Check()
{
    ll sum = 0;
    for (int i = 1; i <= n; ++i)
    {
        sum += num[i];
        if (sum < 1 && i != n)
        {
            return 0;
        }
    }
    if (!sum)
    {
        return 1;
    }
    return 0;
}

int main()
{
    int T = read();
    while (T--)
    {
        n = read();
        for (int i = 1; i <= n; ++i)
        {
            num[i] = read();
        }
        while (!num[n] && n)
        {
            --n;
        }
        if (Check())
        {
            puts("Yes");
        }
        else
        {
            puts("No");
        }
    }
}

D. Fake Plastic Trees

贪心

不难发现叶子节点肯定需要被改一次,那么我们优先跑满叶子节点。叶子节点的祖先们如果加上这个值不够就得多搞一次,多搞的话也是优先选靠下的节点,如果权值超了的话直接改成它的最大值即可。

直接树形DP搞完事

点击查看代码
#include <cstdio>
#include <cstring>
#include <cctype>
#include <iostream>
#include <sstream>
#include <stack>
#include <cmath>
#include <algorithm>
#include <map>
#include <queue>
#include <list>
#include <set>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;

const int maxn = 2e5 + 10, maxe = 2e5 + 10, maxt = maxn * 600;

int read()
{
    int x = 0;
    char c;
    bool f = 0;
    while (!isdigit(c = getchar()))
    {
        if (c == '-')
        {
            f = 1;
        }
    }
    do
    {
        x = (x << 1) + (x << 3) + (c ^ 48);
    } while (isdigit(c = getchar()));
    if (f)
    {
        return -x;
    }
    return x;
}

char getFunc()
{
    char c;
    while (!isalpha(c = getchar()))
    {
    }
    return c;
}

struct Graph
{
    int head[maxn], len;
    int nxt[maxe], to[maxe];
    void Clear(int n)
    {
        for (int i = 1; i <= n; ++i)
        {
            head[i] = 0;
        }
        len = 0;
    }
    void Ins(int u, int v)
    {
        to[++len] = v;
        nxt[len] = head[u];
        head[u] = len;
    }
} G;

ll l[maxn], r[maxn];
ll f[maxn];

int ans = 0;

void DFS(int u, int fa)
{
    if (!G.head[u])
    {
        f[fa] += r[u];
        ++ans;
        return;
    }
    for (int i = G.head[u]; i; i = G.nxt[i])
    {
        int v = G.to[i];
        DFS(v, u);
    }
    ll val = min(f[u], r[u]);
    if (val < l[u])
    {
        ++ans;
        f[fa] += r[u];
    }
    else
    {
        f[fa] += val;
    }
}

int main()
{
    int T = read();
    while (T--)
    {
        int n = read();
        G.Clear(n);
        for (int i = 2; i <= n; ++i)
        {
            G.Ins(read(), i);
        }
        for (int i = 1; i <= n; ++i)
        {
            f[i] = 0;
            l[i] = read(), r[i] = read();
        }
        ans = 0;
        DFS(1, 0);
        printf("%d\n", ans);
    }
}

E. Keshi in Search of AmShZ

好像也是贪心)

我们建反图,在反图上搞

发现其实就是一个 Dijkstra 的变形

设 dis[u] 为节点 u 到达 n 的最小天数

deg[u] 为节点 u 在反图上的入度

我们更新的时候,选择当前 dis[u] 最小的 u 来枚举 u 所连接的每一个节点 v,每处理完一个 v 就 --deg[v],可以发现如果这样做从 u 点往它连接 v 点走所需要的代价是 deg[v]

然后松弛的时候比 dis[u] + deg[v] 和 dis[v] 的大小,跑 Dijkstra 即可。

点击查看代码
#include <cstdio>
#include <cstring>
#include <cctype>
#include <iostream>
#include <sstream>
#include <stack>
#include <cmath>
#include <algorithm>
#include <map>
#include <queue>
#include <list>
#include <set>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;

const int maxn = 2e5 + 10, maxe = 2e5 + 10, maxt = maxn * 600;

int read()
{
    int x = 0;
    char c;
    bool f = 0;
    while (!isdigit(c = getchar()))
    {
        if (c == '-')
        {
            f = 1;
        }
    }
    do
    {
        x = (x << 1) + (x << 3) + (c ^ 48);
    } while (isdigit(c = getchar()));
    if (f)
    {
        return -x;
    }
    return x;
}

char getFunc()
{
    char c;
    while (!isalpha(c = getchar()))
    {
    }
    return c;
}

struct Graph
{
    int head[maxn], len;
    int nxt[maxe], to[maxe];
    void Ins(int u, int v)
    {
        to[++len] = v;
        nxt[len] = head[u];
        head[u] = len;
    }
} G;

typedef pair<int, int> P;

int deg[maxn];
int dis[maxn];
bool vis[maxn];

int Dijkstra(int s)
{
    priority_queue<P, vector<P>, greater<P>> q;
    memset(dis, 0x3f, sizeof dis);
    dis[s] = 0;
    q.push(P(0, s));
    while (!q.empty())
    {
        int u = q.top().second;
        q.pop();
        if (vis[u])
        {
            continue;
        }
        vis[u] = 1;
        for (int i = G.head[u]; i; i = G.nxt[i])
        {
            int v = G.to[i];
            if (dis[u] + deg[v] < dis[v])
            {
                dis[v] = dis[u] + deg[v];
                q.push(P(dis[v], v)); 
            }
            --deg[v];
        }
    }
    return dis[1];
}

int main()
{
    int n = read(), m = read();
    for (int i = 1; i <= m; ++i)
    {
        int u = read(), v = read();
        G.Ins(v, u);
        ++deg[u];
    }
    printf("%d\n", Dijkstra(n));
}

F. Decinc Dividing

DP

好像和题解做法一样)那就粘题解吧

image

点击查看代码
#include <cstdio>
#include <cstring>
#include <cctype>
#include <iostream>
#include <sstream>
#include <stack>
#include <cmath>
#include <algorithm>
#include <map>
#include <queue>
#include <list>
#include <set>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;

const int maxn = 2e5 + 10, maxe = 2e5 + 10, maxt = maxn * 600;

int read()
{
    int x = 0;
    char c;
    bool f = 0;
    while (!isdigit(c = getchar()))
    {
        if (c == '-')
        {
            f = 1;
        }
    }
    do
    {
        x = (x << 1) + (x << 3) + (c ^ 48);
    } while (isdigit(c = getchar()));
    if (f)
    {
        return -x;
    }
    return x;
}

char getFunc()
{
    char c;
    while (!isalpha(c = getchar()))
    {
    }
    return c;
}

int num[maxn];
int fup[maxn], fdown[maxn];

int main()
{
    int n = read();
    ll ans = 0, res = n + 1;
    for (int i = 1; i <= n; ++i)
    {
        num[i] = read();
    }
    for (int i = n; i; --i)
    {
        fup[i] = 0x7fffffff;
        fdown[i] = -1;
        for (int j = i + 1; j <= n; ++j)
        {
            int up = -1, down = 0x7fffffff;
            if (fdown[j - 1] < num[j])
            {
                up = max(up, num[j - 1]);
            }
            if (num[j - 1] < num[j])
            {
                up = max(up, fup[j - 1]);
            }
            if (num[j] < fup[j - 1])
            {
                down = min(down, num[j - 1]);
            }
            if (num[j - 1] > num[j])
            {
                down = min(down, fdown[j - 1]);
            }
            if (up == fup[j] && down == fdown[j])
            {
                break;
            }
            fup[j] = up, fdown[j] = down;
            // printf("%d %d\n", up, down);
            if (up == -1 && down == 0x7fffffff)
            {
                res = j;
                break;
            }
        }
        ans += res - i;
    }
    printf("%lld\n", ans);
}

标签:10,typedef,800,int,CF,long,maxn,div,include
来源: https://www.cnblogs.com/eafoo/p/16397929.html