0328周赛

今天终于得到了一杯奶茶,据说是Aurora家的。

T1 NKOJ 翻转数列

 

 

 思路:水题,当i为奇数时向后添加Ai,否则向前添加Ai,输出答案时,若n为奇数则倒序输出,否则正序。

#pragma GCC optimize(3)

#include <bits/stdc++.h>

using namespace std;

char buf[1 << 22], *p1 = buf, *p2 = buf;
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)

template <class T>
inline void rd(T &a)
{
    char ch = getchar(); T x = 0, f = 1;
    while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
    while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
    a = x;
}

deque <int> Q;

int main()
{
    while (!Q.empty()) Q.pop_back();
    int n;
    rd(n);
    for (int i = 1, x; i <= n; i++) 
    {
        rd(x);
        if (i & 1) Q.push_front(x);
        else Q.push_back(x);
    }if (n & 1) while (!Q.empty()) printf("%d ", Q.front()), Q.pop_front();
    else while (!Q.empty()) printf("%d ", Q.back()), Q.pop_back();
    
}

T2 NKOJ 四倍数列

 

 

 思路:也是水题,考虑搭配问题,显然要让4尽可能跟1搭配,2和2搭配,于是就有了一个想法,就是若能被4整除的数比被4除余1的数多或是等于,那么必然可以做到。但是发现过不了样例,仔细思考发现还有一种情况,就是能被4整除的数比被4除余1的数的个数少1个,但是没有能被2整除的数,如此也满足题意,于是这个题就做完了。

#include <bits/stdc++.h>

using namespace std;

int num[3];

int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 1, x; i <= n; i++)
    {
        scanf("%d", &x);
        if (x % 4 == 0) ++num[2];
        else if (x % 2 == 0) ++num[1];
        else ++num[0];
    }
    if (num[2] >= num[0] || (num[2] == num[0] - 1 && num[1] == 0)) puts("Yes");
    else puts("No");
}

T3 NKOJ 站队

 

 

 思路:就是在一个序列中找最长上升子序列且公差为1。也有另外一种方法就是记录1-n在此数列中出现的位置,如此就可以找最长上升连续子序列。

#include <bits/stdc++.h>

using namespace std;

int a[200005], f[200005];

int main()
{
    int n, ans = 0;
    scanf("%d", &n);
    for (int i = 1, x; i <= n; i++) scanf("%d", &x), a[x] = i;
    for (int i = 1; i <= n; i++)
    {
        if (a[i] > a[i - 1]) f[i] = f[i - 1] + 1;
        else f[i] = 1;
        ans = max(ans, f[i]);
    } printf("%d", n - ans);
}

T4 NKOJ 打针

 

 思路:一开始考虑直接从每个点往下跑,发现会被链卡成麻瓜,于是就反向考虑,从每一个点倍增往上跑,找到能跑到的最上面的点,而这条路径上所有的点都能跑到这个点,等同于说给这条路径上所有的点做出了1的贡献,所以考虑树上差分。

#pragma GCC optimize(3)

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

ll n, s, dist[200005][21], fa[200005][21], dep[200005];

struct node {
    ll to, nxt, len;
}e[400005]; ll head[200005], tot, cnt[200005];
inline void add_e(ll u, ll v, ll w) {e[++tot].to = v; e[tot].nxt = head[u]; head[u] = tot; e[tot].len = w;}

void dfs(ll u)
{
    for (ll i = 1; i <= 20; i++) fa[u][i] = fa[fa[u][i - 1]][i - 1], dist[u][i] = dist[u][i - 1] + dist[fa[u][i - 1]][i - 1];
    for (ll i = head[u]; i; i = e[i].nxt)
    {
        ll v = e[i].to;
        if (v == fa[u][0]) continue;
        fa[v][0] = u, dist[v][0] = e[i].len, dep[v] = dep[u] + 1;
        dfs(v);
    }
}

void search(ll u)
{
//    cnt[u]++;
    for (ll i = head[u]; i; i = e[i].nxt)
    {
        ll v = e[i].to;
        if (v == fa[u][0]) continue;
        search(v);
        cnt[u] += cnt[v];
    }
}

char buf[1 << 22], *p1 = buf, *p2 = buf;
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)

template <class T>
inline void rd(T &a)
{
    char ch = getchar(); T x = 0, f = 1;
    while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
    while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
    a = x;
}

main()
{
    rd(n), rd(s);
    for (ll i = 2, x, y, z; i <= n; i++)
    {
        rd(x), rd(z);
        add_e(x, i, z);
    }
    dfs(1); dep[0] = -1;
    for (ll i = 1 ; i <= n; i++)
    {
        ll dis = 0, u = i, v = i;
        for (ll j = 20; ~j; j--)
        {
            if (dist[u][j] + dis <= s && dep[u] >= 0) dis += dist[u][j], u = fa[u][j];
        }
        cnt[v]++, cnt[fa[u][0]]--;
    } search(1);
    for (ll i = 1; i <= n; i++) printf("%lld\n", cnt[i]);
}

T5 NKOJ 叶子的染色

 

 思路:显然的树形dp,有两个性质:一是以n+1到m任何一个点作为根的结果是一样的,可以手推得出;二是越往上走能够控制的节点越多。有了这两条性质,我们列出状态:f[i][j]表示i节点涂j(0/1)颜色的最小代价。

于是有状态转移方程:f[i][j] += min(f[v][j] - 1, f[v][j ^ 1]) (其中v为i的儿子)(显然若儿子与父亲的颜色一样,则可以擦除儿子的颜色,所以代价减1),做完了。

#include <bits/stdc++.h>

using namespace std;

struct node {
    int to, nxt;
}e[20005]; int head[10005], tot, m, n;
inline void add_e(int u, int v) {e[++tot].to = v; e[tot].nxt = head[u]; head[u] = tot;}
 
int c[5005], f[100005][2];

void dp(int u, int fa)
{
    for (int i = head[u]; i; i = e[i].nxt)
    {
        int v = e[i].to;
        if (v == fa) continue;
        dp(v, u);
        for (int j = 0; j <= 1; j++)
        {
            f[u][j] += min(f[v][j] - 1, f[v][j ^ 1]);
        }
    }
}

int main()
{
    scanf("%d%d", &m, &n);
    for (int i = 1; i <= m; i++) f[i][0] = f[i][1] = 1;
    for (int i = 1, x; i <= n; i++) scanf("%d", &x), f[i][x ^ 1] = 0x3f3f3f3f;
    for (int i = 1, x, y; i < m; i++)
    {
        scanf("%d%d", &x, &y);
        add_e(x, y); add_e(y, x);
    }
    dp(n + 1, 0);
    printf("%d", min(f[n + 1][0], f[n + 1][1]));
}

难得的AK,下次继续努力!!!

posted @ 2021-03-28 18:28  Chasing-Dreams  阅读(97)  评论(0)    收藏  举报