【codeforces】Round #316 (Div. 2)

T1 Elections

題目大意:
有N個候選人,M個城市,每個候選人在不同城市有不同的得票,一個候選人在某個城市得到最多的票就可以贏得一輪選舉,第二輪選舉勝出的條件是在最多的城市勝出,最後輸出候選人的序號。
思路:
蛤蛤,除了不要把m和n讀反,似乎也沒有什麼了

#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define red(i, a, b) for(int i = (a); i >= (b); i--)
#define ll long long

const int N = 200, M = 200;
int n, m;
int a[N][M], vote[M];

int main() {
    scanf("%d%d", &n, &m);
    memset(vote, 0, sizeof(vote));
    rep(i, 1, m) {
        int maxn = -1, maxi = 0;
        rep(j, 1, n) {
            scanf("%d", &a[i][j]);
            if (a[i][j] > maxn) { maxn = a[i][j]; maxi = j; }
        }
        vote[maxi]++;
    }
    int ansn = 0, ansi = 0;
    rep(i, 1, n)
        if (vote[i] > ansn) {
            ansn = vote[i];
            ansi = i;
        }
    printf("%d\n", ansi);
    return 0;
}

T2 Simple Game

題目大意:
你和另一個人分別從選1到n中選一個數字a,b,再隨機出一個c,選擇的數字最接近c的那個人贏,距離一樣時候你輸。給你n和a(那個人選的數字),你輸出獲勝概率最大的數字b
思路:
精妙題
m把區間分成兩部分,若m在左半段,則選m+1,若m在右半段,則選m-1,在中間選m-1
n可能爲1

#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define red(i, a, b) for(int i = (a); i >= (b); i--)
#define ll long long

int n, m;

int main() {
    scanf("%d%d", &n, &m);
    if (n == 1) printf("1\n");
    else if (n & 1) {
        if (m == (n + 1) / 2) printf("%d\n", m - 1);
        else if (m > (n + 1) / 2) printf("%d\n", m - 1);
        else printf("%d\n", m + 1);
    }else {
        if (m > n / 2) printf("%d\n", m - 1);
        else printf("%d\n", m + 1);
    }
    return 0;
}

T3 Replacement

題目大意:
給你一個包含小寫字母和”.”的字符串,對於整個字符串要求一個值,就是相鄰的一對“.”的個數。現有M次詢問,每次給出一個位置和一個字符,更新當前的字符串並求出字符串新的值。
思路:
題目轉化爲求任一位置與它相鄰的非’.’字符的位置,即可更新答案。
用map或者set維護即可

#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define red(i, a, b) for(int i = (a); i >= (b); i--)
#define ll long long
#define PII pair<int, int>

const int N = 333333;
map <int, int> pos;
char str[N];
int n, m, ans;

int main() {
    scanf("%d%d", &n, &m);
    scanf("%s", str);
    ans = 0;
    pos.insert(make_pair(-1, 0));
    pos.insert(make_pair(n, 0));
    rep(i, 0, n - 1) {
        if (str[i] != '.') pos.insert(make_pair(i, 0));
        else if (i > 0 && str[i - 1] == '.') ans++;
    }
    while(m--) {
        char c; int p;
        scanf("%d %c", &p, &c);
        p--;
        map <int, int>::iterator it;
        it = pos.find(p);
        if (it == pos.end()) { // pos p is '.'
            if (c != '.') {
                pos.insert(PII(p, 0));
                it = pos.find(p);
                map<int, int>::iterator it1 = it, it2 = it;
                it1--; it2++;
                int old_ans = it2->first - it1->first - 2;
                if (old_ans < 0) old_ans = 0;
                int new1 = it->first - it1->first - 2;
                if (new1 < 0) new1 = 0;
                int new2 = it2->first - it->first - 2;
                if (new2 < 0) new2 = 0;
                ans += new1 + new2 - old_ans;
            }
        }else { // pos p is a char
            if (c == '.') {
                map<int, int>::iterator it1 = it, it2 = it;
                it1--; it2++;
                int new_ans = it2->first - it1->first - 2;
                int old1 = it->first - it1->first - 2;
                if (old1 < 0) old1 = 0;
                int old2 = it2->first - it->first - 2;
                if (old2 < 0) old2 = 0;
                ans += new_ans - old1 - old2;
                pos.erase(it);
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

T4 Tree Requests

題目大意:
給你一個樹,保證父節點序號小子節點序號,根節點序號爲1,每個節點有一個字母。M次詢問,給一個v和h,問以v爲祖先的深度爲h的所有節點對應的字母是否能夠成迴文字符串。
思路:
1.考慮dfs序,給節點重新標號,那麼就可以使一顆子樹的節點序號是連續的,並且保證深度相同的節點的標號是遞增的。
2.按順序記錄每層節點的標號
3.每個節點記錄一下以這個節點爲根的子樹的序號範圍,那麼就可以用兩次二分來找到第h層節點中屬於以這個節點爲祖先的節點區間。
4.利用前綴異或和來O(1)判斷這個區間的節點是否滿足條件

#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define red(i, a, b) for(int i = (a); i >= (b); i--)

int N, M;
const int SIZE = 500005;
int l[SIZE], r[SIZE];
vector <int> pos[SIZE], num[SIZE], g[SIZE];
char s[SIZE];
int no = 1;

void dfs(int u, int d) {
    l[u] = no++;
    pos[d].push_back(l[u]);
    num[d].push_back(num[d].back() ^ (1 << (s[u] - 'a')));
    for(int i = 0; i < g[u].size(); i++) {
        dfs(g[u][i], d + 1);
    }
    r[u] = no;
}

int lowbit(int k) { return k & (-k); }

int popCount(int n) {
    int cnt = 0;
    while(n) {
        cnt++;
        n -= lowbit(n);
    }
    return cnt;
}

int main() {
    scanf("%d%d", &N, &M);
    rep(i, 2, N) {
        int n;
        scanf("%d", &n);
        g[n].push_back(i);
    }
    scanf("%s", s + 1);
    rep(i, 1, N) {
        num[i].push_back(0);
        pos[i].push_back(0);
    }
    dfs(1, 1);
    while(M--) {
        int x, d;
        scanf("%d%d", &x, &d);
        int st, en;
        st = lower_bound(pos[d].begin(), pos[d].end(), l[x]) - pos[d].begin() - 1;
        en = lower_bound(pos[d].begin(), pos[d].end(), r[x]) - pos[d].begin() - 1;
        if (popCount(num[d][en] ^ num[d][st]) <= 1) puts("Yes");
        else puts("No");
    }
    return 0;
}

T5 Pig And Palindromes

題目大意:
求一個矩陣中,從左上角到右下角有幾條路徑是嚴格的迴文串
基本思路:
f[x1][y1][x2][y2]表示從(1,1)到(x1,y1)與從(n,m)到(x2,y2)完全匹配的方案數,上下左右四個方向向下轉移
若總長爲奇數,用對角線上的點統計答案
若總廠爲偶數,稍微複雜一些,需要枚舉可行的點對
優化方法:
優化狀態,用f[x1][y1][x2]表示狀態,y2可以計算

#include <bits/stdc++.h>
using namespace std;
const int N = 500 + 5;
const int MOD = 1000000007;
int f[2][N][N];
char s[N][N];
int main(){
    int n, m, x, y;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            scanf(" %c", &s[i][j]);
    f[0][0][0] = 1;
    for (int l = 1; l <= (n + m) / 2; l++){
        int i = l & 1, j = i ^ 1;
        memset(f[i], 0, sizeof(f[i]));
        for (int ix = max(1, l - m + 1); ix <= min(n, l); ix++)
            for (int jx = max(1, l - m + 1); jx <= min(n, l); jx++)
                if (s[ix][l - ix + 1] == s[n - jx + 1][jx + m - l]){
                    f[i][ix][jx] = ((f[j][ix][jx] + f[j][ix - 1][jx - 1]) % MOD 
                                  + (f[j][ix - 1][jx] + f[j][ix][jx - 1]) % MOD) % MOD;
                }
    }
    int l = (n + m) / 2, i = l & 1, ans = 0;
    if ((m + n - 1) % 2) 
        for (int ix = max(1, l - m + 1); ix <= min(n, l); ix++)
            ans = (ans + f[i][ix][n - ix + 1]) % MOD;
    else
        for (int ix = max(1, l - m + 1); ix <= min(n, l); ix++)
            ans = ((ans + f[i][ix][n - ix]) % MOD + f[i][ix][n - ix + 1])% MOD;
    printf("%d", ans);
}

尾聲

T1怒WA三發,由於HBH和我一樣SB,所以總共WA六發
Team Ranking爆炸
第三題黨內出現了分歧,然而殊途同歸
沒有GJ的Team智商落入平均線下
有人被水錶了-_-||

End.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章