A
题意:
每行代表一个城市每列的选举人的投票,投票最多的表明该城市支持他,如果支持的人数相同,则选小的,求获得最多城市支持的人。
解析:
直接模拟就好了。
my code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 105;
int candid[N], winer[N];
int a[N];
int n, m;
int main() {
int val;
while(scanf("%d%d", &n, &m) != EOF) {
memset(winer, 0, sizeof(winer));
for(int i = 1; i <= m; i++) {
memset(candid, 0, sizeof(candid));
for(int i = 1; i <= n; i++) {
scanf("%d", &val);
candid[i] += val;
}
int maxv = -INF, maxp = 0;
for(int i = 1; i <= n; i++) {
if(candid[i] > maxv) {
maxv = candid[i];
maxp = i;
}
}
winer[maxp]++;
}
int maxv = -INF, maxp = 0;
for(int i = 1; i <= n; i++) {
if(winer[i] > maxv) {
maxv = winer[i];
maxp = i;
}
}
printf("%d\n", maxp);
}
return 0;
}
B
题意:
知道总共可以选的数,和Misha选的数,求Andrew选一个能让尽可能多的数到Andrew的距离比Misha更近。
解析:
我们再数轴上来看:
显然,如果m到n的长度比1到m大很多,andrew选择m+1至少右边所有的他都能比misha近。
同理,如果左边比右边长,那么就选m-1这个点。
如果左边和右边相等,题目要求说If there are multiple such values, print the minimum of them.要求我们打印小的,也就是m-1。
特别的,当n=1的时候,只能选择数1,所以输出1。
my code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n, m;
int main() {
while(scanf("%d%d", &n, &m) != EOF) {
int left = m - 1, right = n - m;
if(left < right) {
printf("%d\n", min(m+1, n));
}else {
printf("%d\n", max(m-1, 1));
}
}
return 0;
}
C
给你一个字符串带有点的,连续的两个点可以变成一个点。
f(s)操作是说连续把两个点变成一个点最少操作
然后有m次询问,每次把x位置上的字符变成c,先变完,再询问每次的f(s)
解析:
先扫一遍整个字符串,如果发现连续两个”.”的情况,答案就加一,然后对每次询问中的替换:如果由小写字母换成小写字母或者由”.”换成”.”则显然不影响答案,如果是由字母替换成”.”,则查询该位置左右的字符,如果有一个”.”说明这次更改使得答案增加了一,左右侧都有”.”则答案加二
同样的道理,如果替换是由”.”换成字母,同样查询左右位置的字符,如果是”.”则答案减一,道理同上。
my code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = (int)3e5 + 10;
char str[MAXN];
int n, m;
int main() {
while(scanf("%d%d", &n, &m) != EOF) {
scanf("%s", str+1);
int ans = 0;
for(int i = 1; i <= n; i++) {
if(str[i] == '.' && str[i+1] == '.')
ans++;
}
int x;
char c[5];
while(m--) {
scanf("%d%s", &x, c);
if(c[0] == '.') {
if(str[x] != '.') {
if(x + 1 <= n && str[x+1] == '.')
ans++;
if(x - 1 > 0 && str[x-1] == '.')
ans++;
}
str[x] = c[0];
printf("%d\n", ans);
}else {
if(str[x] == '.') {
if(x + 1 <= n && str[x+1] == '.')
ans--;
if(x - 1 > 0 && str[x-1] == '.')
ans--;
}
str[x] = c[0];
printf("%d\n", ans);
}
}
}
return 0;
}
D
题意:
给你一个树形的图,先输入的是每个孩子所指向的父亲节点的编号,
然后询问的是,以v为根,深度为h的子树节点,能否构成回文串。
解析:
26个字母看成一个二进制位,如果最后二进制位1个数>=2就不是回文了,由于要计算子树,可以这样处理,pre[d] 数组存的是当前这一层d所有的异或和,dfs进去之前,先计算一下前缀和,进去之后,再计算一次异或和,这样两次异或的前缀会被抵消掉,就相当于是求子树的异或和状态了。
my code
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define pb push_back
using namespace std;
const int N = 500005;
vector<int> G[N], Q[N];
int h[N];
int res[N], pre[N];
char str[N];
int n, m;
void init() {
memset(res, 0, sizeof(res));
for(int i = 1; i <= n; i++) {
G[i].clear(), Q[i].clear();
}
}
void dfs(int u, int de) {
for(int i = 0; i < Q[u].size(); i++) {
int id = Q[u][i];
res[id] ^= pre[h[id]];
}
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
dfs(v, de+1);
}
pre[de] ^= (1<<(str[u] - 'a'));
for(int i = 0; i < Q[u].size(); i++) {
int id = Q[u][i];
res[id] ^= pre[h[id]];
}
}
bool judge(int num) {
if(num == 0) return true;
int cnt = 0;
while(num) {
if(num & 1) cnt++;
num >>= 1;
}
return cnt == 1;
}
int main() {
while(scanf("%d%d", &n, &m) != EOF) {
init();
int fa;
for(int i = 2; i <= n; i++) {
scanf("%d", &fa);
G[fa].pb(i);
}
scanf("%s", str+1);
int V, H;
for(int i = 1; i <= m; i++) {
scanf("%d%d", &V, &H);
Q[V].pb(i);
h[i] = H;
}
dfs(1, 1);
for(int i = 1; i <= m; i++) {
puts(judge(res[i]) ? "Yes" : "No");
}
}
return 0;
}