【codeforces】Round #316 (Div. 2)

5 篇文章 0 订阅
2 篇文章 0 订阅

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.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值