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智商落入平均线下
有人被水表了-_-||