2020 年 “游族杯” 全国高校程序设计网络挑战赛

我同学叫我去打的。
不说了,题还是不错的,但奈何我英语差。。。

A. Amateur Chess Players

不想解释。

#include "bits/stdc++.h"

using namespace std;
#define ll long long
#define SZ(x) ((int)(x.size()))
#define all(x) (x).begin(),(x).end()

const ll mod = 998244353;
const int maxn = 100000 + 10;

int main() {
    int n, m;
    scanf("%d", &n);
    string s1, s2;
    for (int i = 1; i <= n; i++) cin >> s1;
    scanf("%d", &m);
    for (int i = 1; i <= m; i++) cin >> s2;
    if (n > m) puts("Cuber QQ");
    else puts("Quber CC");
    return 0;
}

B. Binary String

感觉很难,有点难得读,不想看,也不会。

C. Coronavirus Battle

题意:给n个三维点,一个点1能保护另一个点2的条件是, x 1 < = x 2 , y 1 < = y 2 , z 1 < = z 2 x_1<=x_2,y1<=y_2,z_1<=z_2 x1<=x2,y1<=y2,z1<=z2并至少有一维要明确小于。如果一个点没有被保护,就直接死去,叫你看看每个点能存活多久。
我读出来是这样的,但不过我写得能过的代码好像当几个点一样时,有点问题,不想改了,不是很懂,或许数据没有相等?
做法:是不是三维偏序,但不过又和三维偏序不一样,考虑cdq做法,按照 x x x排序,假设 l , m i d l,mid l,mid点的点对处理好了,接下来出了 m i d + 1 , r mid+1,r mid+1,r的点对,首先对于 m i d + 1 , r mid+1,r mid+1,r可以自己处理,我们考虑 l , m i d l,mid l,mid对其的印象,因为第一次排序肯定是 l , m i d l,mid l,mid x x x是小于等于 m i d + 1 , r mid+1,r mid+1,r,然后就是对他们可以进行 y y y排序,然后对于前半部分和后半部分,维护一个前缀最大值就可以了(三维偏序好像是前缀和)。
我的前队友秒杀此题 tql
前面的代码写得很丑,因为写炸了。。。
下面放一个好看代码。

#include "bits/stdc++.h"

using namespace std;
#define ll long long
#define SZ(x) ((int)(x.size()))
#define all(x) (x).begin(),(x).end()
#define ull unsigned long long

const int maxn = 100000 + 10;
unsigned long long k1, k2;
unsigned long long CoronavirusBeats() {
    unsigned long long k3 = k1, k4 = k2;
    k1 = k4;
    k3 ^= k3 << 23;
    k2 = k3 ^ k4 ^ (k3 >> 17) ^ (k4 >> 26);
    return k2 + k4;
}

int n, dp[maxn];
struct node {
    ull x, y, z;
    int id, flag;
} num[maxn], tmp[maxn];

bool cmp(node a, node b) {
    if (a.x == b.x) {
        if (a.y == b.y)return a.z < b.z;
        return a.y < b.y;
    }
    return a.x < b.x;
}
bool cmp1(node a, node b) {
    return a.y < b.y;
}
int low[maxn];
#define lowbit(x) (x&-x)
void update(int x, int val) {
    for (; x < maxn; x += lowbit(x)) low[x] = max(low[x], val);
}
int query(int x) {
    int ret = 0;
    for (; x; x -= lowbit(x)) ret = max(ret, low[x]);
    return ret;
}
void Clear(int x) {
    for (; x < maxn; x += lowbit(x)) low[x] = 0;
}

void cdq(int l, int r) {
    if (l == r) return;
    int mid = (l + r) >> 1;
    cdq(l, mid);
    int tot = 0;
    for (int i = l; i <= mid; i++) {
        tmp[++tot] = num[i];
        tmp[tot].flag = 0;
    }
    for (int i = mid + 1; i <= r; i++) {
        tmp[++tot] = num[i];
        tmp[tot].flag = 1;
    }
    sort(tmp + 1, tmp + tot + 1, cmp1);
    for (int i = 1; i <= tot; i++) {
        if (tmp[i].flag == 0) update(tmp[i].z, dp[tmp[i].id]);
        else dp[tmp[i].id] = max(dp[tmp[i].id], query(tmp[i].z) + 1);
    }
    for (int i = 1; i <= tot; i++)
        if (tmp[i].flag == 0) Clear(tmp[i].z);
    cdq(mid + 1, r);
    return;
}

vector<ull> v;
int main() {
    cin >> n >> k1 >> k2;
    for (int i = 1; i <= n; i++) {
        ull x, y, z;
        x = CoronavirusBeats();
        y = CoronavirusBeats();
        z = CoronavirusBeats();
        num[i] = node{x, y, z, i};
        v.push_back(z);
        dp[i] = 1;
    }
    sort(v.begin(), v.end());
    v.erase(unique(v.begin(), v.end()), v.end());
    for (int i = 1; i <= n; i++) {
        num[i].z = lower_bound(v.begin(), v.end(), num[i].z) - v.begin() + 1;
    }
    sort(num + 1, num + 1 + n, cmp);
    cdq(1, n);

    int ans = 0;
    for (int i = 1; i <= n; i++) ans = max(ans, dp[i]);
    cout << ans << endl;
    for (int i = 1; i <= n; i++) {
        cout << dp[i] - 1 << " ";
    }
    puts("");
    return 0;
}

D. Decay of Signals

题意:给你一个树,叫你求所有路径中的最大的这个东西 ∏ i ∈ ( u , v ) a i / m \prod_{i\in(u,v)}a_i/m i(u,v)ai/m的最小值,其中m是路径的长度,当时我前队友给我说,直接一句点分治。
做法:后来当我看见点权的范围,我瞬间不想做了,哪儿来的什么点分治额。其实也不是很难,假设当一条路径新加入一个点进去,我们会发现原来的式子变成了原来的 m ∗ a i / ( m + 1 ) m*a_i/(m+1) mai/(m+1)这个点权如果是1肯定是变小,如果是2以上,就有变大,当然2也有可能不变,然后思路就有了,维护每个点直接相连的1链的长度,只要次长和最长就可以了,但不过也不好写,我错了好多发,还有些坑。
这里我用的树 dp,首先维护儿子的1的长度,然后再换根。
维护出1的长度,答案就很好求了,每个点的最小值就是 a i / ( l 1 + l 2 + 1 ) a_i/(l1+l2+1) ai/(l1+l2+1)

#include "bits/stdc++.h"

using namespace std;
#define ll long long
#define SZ(x) ((int)(x.size()))
#define all(x) (x).begin(),(x).end()
#define ull unsigned long long

const int maxn = 1000000 + 10;
const ll inf = 1e18;
struct edge {
    int u, v, nxt;
} ed[maxn << 1];
int head[maxn << 1], cnt;
void add_e(int u, int v) {
    ed[++cnt] = edge{u, v, head[u]};
    head[u] = cnt;
}
int n, col[maxn], f[maxn][2], s[maxn][2];

void dfs(int u, int fa) {
    int mlen1 = 0, s1 = 0, mlen2 = 0, s2 = 0;
    for (int i = head[u]; i; i = ed[i].nxt) {
        int v = ed[i].v;
        if (v == fa) continue;
        dfs(v, u);
        int k;
        if (col[v] == 1) k = 1 + f[v][0];
        else k = 0;
        if (k > mlen1) {
            mlen2 = mlen1;
            s2 = s1;
            mlen1 = k;
            s1 = v;
        } else if (k > mlen2) {
            mlen2 = k;
            s2 = v;
        }
    }
    f[u][0] = mlen1, f[u][1] = mlen2;
    s[u][0] = s1, s[u][1] = s2;
}

void dfs1(int u, int fa) {
    if (col[fa] == 1) {
        int t1 = f[fa][0], son = s[fa][0];
        if (son == u) {
            t1 = f[fa][1], son = s[fa][1];
        }
        if (t1 + 1 > f[u][0]) {
            f[u][1] = f[u][0];
            s[u][1] = s[u][0];
            f[u][0] = t1 + 1;
            s[u][0] = fa;
        } else if (t1 + 1 > f[u][1]) {
            f[u][1] = t1 + 1;
            s[u][1] = fa;
        }
    }
    for (int i = head[u]; i; i = ed[i].nxt) {
        int v = ed[i].v;
        if (v != fa) dfs1(v, u);
    }
}

int main() {
    scanf("%d", &n);
    for (int i = 1, u, v; i < n; i++) {
        scanf("%d%d", &u, &v);
        add_e(u, v);
        add_e(v, u);
    }
    int mx = 1e9;
    for (int i = 1; i <= n; i++) {
        scanf("%d", &col[i]);
        mx = min(mx, col[i]);
    }
//    sort(col + 1, col + n + 1);
    if (mx == 0) {
        printf("0/1\n");
    } else if (mx > 1) {
        printf("%d/1", mx);
    } else {
        dfs(1, 0);
        dfs1(1, 0);
        ll ans1 = col[1], ans2 = f[1][0] + f[1][1] + 1;
        for (int i = 2; i <= n; i++) {
            if (col[i] > 2) continue;
            ll t1 = col[i], t2 = f[i][0] + f[i][1] + 1;
            if (t1 * ans2 < t2 * ans1)
                ans1 = t1, ans2 = t2;
        }
        ll g = __gcd(ans1, ans2);
        ans1 /= g, ans2 /= g;
        printf("%lld/%lld\n", ans1, ans2);
    }
    return 0;
}

E. Even Degree

这道题没怎么看,后来听他们说很简单。
题意:给出一个无向图,他不能删除两个点度数都是奇数的变,问最多能删除多少条边,删除是一个动态过程,即如果你删了一条边,这条边的两个节点的度数会减一,给出的图每个点的度数都是偶数。
做法:本人本来就不会什么图论,然后幸好栞过宋聚聚的欧拉回路,然后就知道一个欧拉回路,做法就是找到欧拉回路,然后随便删除一条边,在从两边删除着走就行了。
这道题给差评卡了我,幸好第二天代码公开,学了一写技术。

#include "bits/stdc++.h"

using namespace std;
#define ll long long
#define ull unsigned long long
#define SZ(x) ((int)(x.size()))
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second

const ll mod = 998244353;
const int maxn = 500000 + 10;
struct node {
    int u, v, id;
} e[maxn];
vector<pair<int, int> > g[maxn];
int n, m, vis[maxn], sta[maxn], mp[maxn], top;
vector<int> ans;
void dfs(int u) {
    mp[u] = 1;
    while (SZ(g[u]) != 0) {
        pair<int, int> x = g[u][SZ(g[u]) - 1];
        g[u].pop_back();
        if (vis[x.se]) continue;
        vis[x.se] = 1;
        dfs(x.fi);
        sta[++top] = x.se;
    }
}

void Delete(int t) {
    int u = e[sta[1]].u, v = e[sta[1]].v;
    ans.push_back(sta[1]);
    int l = 2, r = t;
    while (l < r) {
        int tu = e[sta[l]].u, tv = e[sta[l]].v;
        if (max(tu, tv) != max(u, v) || min(tu, tv) != min(u, v)) {
            ans.push_back(sta[l++]);
            if (u == tu) u = tv;
            else if (u == tv) u = tu;
            if (v == tv) v = tu;
            else if (v == tu) v = tv;
        } else {
            tu = e[sta[r]].u, tv = e[sta[r]].v;
            ans.push_back(sta[r--]);
            if (u == tu) u = tv;
            else if (u == tv) u = tu;
            if (v == tv) v = tu;
            else if (v == tu) v = tv;
        }
    }
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1, u, v; i <= m; i++) {
        scanf("%d%d", &u, &v);
        g[u].push_back({v, i});
        g[v].push_back({u, i});
        e[i] = node{u, v, i};
    }
    for (int i = 1; i <= n; i++) {
        if (mp[i]) continue;
        top = 0;
        dfs(i);
        if (top == 0) continue;
        Delete(top);
    }
    cout << SZ(ans) << endl;
    for (auto x:ans) cout << x << " ";
    cout << endl;
}

F. Find / -type f -or -type d

这道题就是叫你求.eoj后缀的字符串个数,而且这个字符串不能是别的字符串的前缀吧。
不解释字符串哈希,怕被卡就双哈希,好像其他算法也能做。

#include "bits/stdc++.h"

using namespace std;
#define ll long long
#define SZ(x) ((int)(x.size()))
#define all(x) (x).begin(),(x).end()
#define ull unsigned long long

const ll mod = 998244353;
const int maxn = 100000 + 10;
const ull p = 3145739;
string s[maxn];
ull has[maxn];
unordered_map<ull, int> mp;
int main() {
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        cin >> s[i];
        ull ha1 = 0;
        int len = s[i].size();
        for (int j = 0; j < len; j++) {
            ha1 = ha1 * p + s[i][j];
            if (j != len - 1) mp[ha1] = 1;
        }
        has[i] = ha1;
    }
    int ans = 0;
    for (int i = 0; i < n; i++) {
        int len = s[i].size();
        if (len < 4) continue;
        if (s[i][len - 1] == 'j' && s[i][len - 2] == 'o' && s[i][len - 3] == 'e' && s[i][len - 4] == '.') {
            if (mp[has[i]] != 1) {
                ans++;
                mp[has[i]] = 1;
            }
        }
    }
    cout << ans << endl;
    return 0;
}

G. Geralt of Rivia

没读,不会。

H. Heat Pipes

题意:一个图吧,然后相邻点的点权相差为1 ,叫你染色,点权的范围a到b,这个范围都要染上。
做法:又是图论题,想了想对与一个图只要找到最长链就可以了,在问了问宋聚聚之后是图的直径,好像只有用bfs求,具体看代码吧,写法比较固定。

#include "bits/stdc++.h"

using namespace std;
#define ll long long
#define ull unsigned long long
#define SZ(x) ((int)(x.size()))
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second

const ll mod = 998244353;
const int maxn = 2000 + 10;
const double pi = acos(-1.0);
int n, m, a, b;
vector<int> g[maxn], f;
int vis[maxn], flag, col[maxn];

void dfs(int u, int color) {
    vis[u] = color;
    f.push_back(u);
    for (auto v:g[u]) {
        if (flag) return;
        if (vis[v] == vis[u]) {
            flag = 1;
            return;
        }
        if (vis[v] == 0) dfs(v, -color);
    }
}

int dis[maxn];
int bfs(int st, int be) {
    for (int i:f) dis[i] = 10000000;
    dis[st] = 1;
    if (be != -1) col[st] = be;
    queue<int> qu;
    qu.push(st);
    int mx = 0;
    while (!qu.empty()) {
        int u = qu.front();
        qu.pop();
        mx = max(mx, dis[u]);
        for (auto v:g[u]) {
            if (dis[v] > dis[u] + 1) {
                dis[v] = dis[u] + 1;
                qu.push(v);
                if (be != -1) {
                    col[v] = (col[u] == b) ? col[u] - 1 : col[u] + 1;
                }
            }
        }
    }
    return mx;
}

int main() {
    int _;
    for (scanf("%d", &_); _; _--) {
        scanf("%d%d%d%d", &n, &m, &a, &b);
        for (int i = 0; i <= n; i++) {
            vis[i] = 0;
            g[i].clear();
        }
        flag = 0;
        for (int i = 1, u, v; i <= m; i++) {
            scanf("%d%d", &u, &v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        if (a >= b) {
            if (m != 0) puts("No");
            else {
                puts("Yes");
                for (int i = 1; i <= n; i++) printf("%d ", a);
                puts("");
            }
            continue;
        }
        int ans = 0;
        int now = a;
        for (int i = 1; i <= n; i++) {
            if (vis[i] != 0) continue;
            if (flag == 1) break;
            f.clear();
            dfs(i, -1);
            now = min(a + ans, b);
            int vmax = -1, st = 0;
            for (int x:f) {
                int t = bfs(x, -1);
                if (t > vmax) {
                    vmax = t;
                    st = x;
                }
            }
            ans += vmax;
            bfs(st, now);
        }
        if (flag || ans < b - a + 1 || b < a) puts("No");
        else {
            puts("Yes");
            for (int i = 1; i <= n; i++) printf("%d ", col[i]);
            puts("");
        }
    }
    return 0;
}

I. Idiotic Suffix Array

不说了,关键是读懂题

#include "bits/stdc++.h"

using namespace std;
#define ll long long
#define SZ(x) ((int)(x.size()))
#define all(x) (x).begin(),(x).end()

const ll mod = 998244353;
const int maxn = 100000 + 10;


int main() {
    int n, k;
    string s = "";
    scanf("%d%d", &n, &k);
    for (int i = 1; i < k; i++) {
        s += 'b';
    }
    s += 'a';
    for (int i = k + 1; i <= n; i++) s += 'd';
    cout << s << endl;
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值