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