1. 程式人生 > 其它 >AtCoder Regular Contest 105

AtCoder Regular Contest 105


菜的真實
T3,T4卡大題還行

C - Camels and Bridge

首先看資料範圍肯定不是一個多項式複雜度的演算法

考慮列舉全排列,那麼怎麼判斷頭尾最短的長度是多少呢?

其實也不難,只要把每個連續段開到必須要開長度,然後大的繼承小的即可

具體實現可以看程式碼

code:

#include<bits/stdc++.h>
using namespace std;
const int N = (1 << 8) + 5;
int n, m, a[15], sum[N], g[N], f[15], id[15];
int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
    sort(a + 1, a + 1 + n);
    for(int S = 0; S < (1 << n); S ++)
        for(int i = 1; i <= n; i ++) if((S >> (i - 1)) & 1) sum[S] += a[i];
    
    while(m --) {
        int l, s;
        scanf("%d%d", &l, &s);
        if(s < a[n]) {
            printf("-1");
            return 0;
        }
        for(int S = 0; S < (1 << n); S ++) 
            if(sum[S] > s) g[S] = max(g[S], l); 
    }
    for(int i = 1; i <= n; i ++) id[i] = i;
    int ans = 1e9;
    do {
        for(int i = 1; i <= n; i ++) f[i] = 0;
        for(int i = 1; i <= n; i ++) {
            int S = (1 << (id[i] - 1));;
            for(int j = i + 1; j <= n; j ++) {
                S |= (1 << (id[j] - 1));
                f[j] = max(f[j], f[i] + g[S]);
            }
        }
        ans = min(ans, f[n]);
    } while(next_permutation(id + 1, id + 1 + n));
    printf("%d", ans);
    return 0;
}

D - Let's Play Nim

可以看出來要滿足全部移到盤子後,最後一個人要儘量讓盤子上的抑或和為0,否則下一個人必勝

那麼如果\(n\)為奇數,最後一次移動一定是先手,那麼後手只需要瞎搗亂,把一半以上的疊到一個上面就行了所以後手必贏

如果\(n\)為偶數,如果可以對稱的放(即每個數出現次數都是偶數次)那麼後手必勝,否則先手必勝

code:

#include<bits/stdc++.h>
#define N 200050
using namespace std;
int n, a[N];
void solve() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
    if(n & 1) {
        printf("Second\n");
        return ;
    }
    sort(a + 1, a + 1 + n);
    //for(int i = 1; i <= n; i ++) printf("%d ", a[i]); printf("\n");
    for(int i = 2; i <= n; i += 2) if(a[i] != a[i - 1]) {
        printf("First\n");
        return ;
    }
    printf("Second\n");
}
int t;
int main() {
    scanf("%d", &t);
    while(t --) solve();
    return 0;
}

E - Keep Graph Disconnected

又是博弈
如果

賀一發楊隊的分析

code:

#include<bits/stdc++.h>
#define N 200050
using namespace std;
int vis[N], n, m, gs;
vector<int> g[N];
void dfs(int u) {
    if(vis[u]) return ; gs ++;
    vis[u] = 1;
    for(int v : g[u]) 
        dfs(v);
}
void solve() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i ++) g[i].clear(), vis[i] = 0;
    for(int i = 1; i <= m; i ++) {
        int u, v;
        scanf("%d%d", &u, &v);
        g[u].push_back(v), g[v].push_back(u);
    } 

    if(n & 1) {
        if((1ll * n * (n - 1) / 2 - m) & 1) printf("First\n");
        else printf("Second\n");
        return ;
    }

    gs = 0; dfs(1); int s = gs; gs = 0; dfs(n); int ss = gs;
    if((s + ss) & 1) {
        printf("First\n");
        return ;
    }
    if((1ll * n * (n - 1) / 2 - 1ll * s * ss - m % 2) & 1) printf("First\n");
    else printf("Second\n");
}
int t;
int main() {
    scanf("%d", &t);
    while(t --) solve();
    return 0;
}