http://codeforces.com/gym/101341
其實我覺得這份題很不錯的,雖然是div2,但是感覺對我挺有幫助(我比較垃圾0.0),還沒補完(做的時候一直蒙逼,要補很多題)先寫一點點的題解,后面的以后補上。
A:
B:這題有一個bug就是,當你一個"happiness"都沒有的時候,你交換哪一個?如果隨機輸出的話是有bug的,就是比如你交換1和2,(注意都是要不同的pos),那么我構造ahppiness,就錯了,交換后出現就不行了。所以還要自己處理一下。我是找有沒有兩個相同的字母,有就交換他們,就相當於沒變了,沒有的話,就不會出現"pp"和"ss",怎么交換都是成立的。

#include <bits/stdc++.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; const int maxn = 2e5 + 20; char str[maxn]; char sub[] = "0happiness"; int lensub; vector<int>pos[222]; void work() { scanf("%s", str + 1); int lenstr = strlen(str + 1); int beOne = 0, enOne = 0, beTwo = 0, enTwo = 0; char ch[22] = {0}; for (int i = 1; i <= lenstr; ++i) { for (int j = 1; j <= 8; ++j) ch[j] = ch[j + 1]; ch[9] = str[i]; pos[str[i]].push_back(i); if (strcmp(ch + 1, sub + 1) == 0) { if (beOne == 0) { beOne = i - 8; enOne = i; continue; } if (beTwo == 0) { beTwo = i - 8; enTwo = i; continue; } printf("NO\n"); return; } } // printf("%d %d %d %d\n", beOne, enOne, beTwo, enTwo); printf("YES\n"); if (!beOne && !beTwo) { for (int i = 'a'; i <= 'z'; ++i) { if (pos[i].size() >= 2) { printf("%d %d\n", pos[i][0], pos[i][1]); return; } } printf("1 %d\n", lenstr); return; } if (!beTwo) beTwo = 1; while (str[beTwo] == str[beOne]) beTwo++; printf("%d %d\n", beOne, beTwo); } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif lensub = strlen(sub + 1); work(); return 0; }
C:推公式貌似有點難度,做的時候一直想着推公式,分類討論太亂了。然后吃了個飯回來想到可以二分答案。二分答案val,判定條件是:首先對於每一種求,最多只能拿Min(val, a + c)個,然后判斷其是否> n,

#include <bits/stdc++.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; LL a, b, c, n, m; bool check(LL val) { LL ra = min(val, a + c); LL rb = min(val, b + c); return ra <= n && rb <= m; } void work() { cin >> a >> b >> c >> n >> m; LL be = 0, en = a + b + c; // cout << check(3) << endl; while (be <= en) { LL mid = (be + en) >> 1; if (check(mid)) be = mid + 1; else en = mid - 1; } cout << en << endl; } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif work(); return 0; }
D:簽到題,對於一個數,可以向左跳或者向右跳,相當於可以加,可以減。回顧ax + by = c是否有整數解,只需要gcd(a, b) | c
這是擴展歐幾里德的內容,現在擴展到n個,一樣的gcd即可。(比賽的時候還卡了這題,哭)

#include <bits/stdc++.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; map<int, bool>vis, ans; const int maxn = 200000 + 20; int a[maxn], n; const int low = -1e9, high = 1e9; int x; void work() { scanf("%d%d", &n, &x); scanf("%d", a + 1); int gg = a[1]; for (int i = 2; i <= n; ++i) { scanf("%d", a + i); gg = __gcd(gg, a[i]); } if (x % gg == 0) printf("YES\n"); else printf("NO\n"); } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif work(); return 0; }
E:這題我寫得很復雜,也沒看懂別人如何貪心,我是直接化公式,然后暴力segment tree維護。思路是,他從t1開始,首先把它左邊的點都暴力走過去,因為沒有其他方法了,然后,就是在[t1, t2]這段路上,選一個點(可能不選),走過去,然后走回t1傳送去t2,然后從t2走去左邊剩下的點,再走回來。一共花費的時間是,假如[t1, t2]這里有兩個點pos[1], pos[2],那么花費的時間是,(pos[1] - t1) * 2 + (t2 - pos[2]) * 2 = 2 * (t2 - t1) + 2 * (pos[1] - pos[2]),所以應該選一個pos[i] - pos[i + 1]最小的去走,線段樹維護。很復雜啦寫的,

#include <bits/stdc++.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; const int maxn = 200000 + 20; #define root 1, m, 1 #define lson L, mid, cur << 1 #define rson mid + 1, R, cur << 1 | 1 LL a[maxn], b[maxn]; LL dis[maxn]; LL mi[maxn << 2]; void pushUp(int cur) { mi[cur] = min(mi[cur << 1], mi[cur << 1 | 1]); } void build(int L, int R, int cur) { if (L == R) { mi[cur] = dis[L]; return; } int mid = (L + R) >> 1; build(lson); build(rson); pushUp(cur); } LL ask(int be, int en, int L, int R, int cur) { if (be > en) return inf + inf; if (L >= be && R <= en) { return mi[cur]; } int mid = (L + R) >> 1; LL ans = inf + inf; if (be <= mid) { ans = ask(be, en, lson); } if (en > mid) { ans = min(ans, ask(be, en, rson)); } return ans; } void work() { int n, m; scanf("%d%d", &n, &m); for (int i = 1; i <= n; ++i) cin >> a[i]; for (int i = 1; i <= m; ++i) { cin >> b[i]; if (i > 1) { dis[i - 1] = b[i - 1] - b[i]; } } dis[m] = inf + inf; build(root); a[n + 1] = inf; LL sumTime = 0; int pb = 1, pa = 1; if (b[pb] <= a[1]) { sumTime += 2 * (a[1] - b[pb]); } while (pb <= m && b[pb] <= a[1]) pb++; while (pb <= m) { if (pa == n) { sumTime += (b[m] - a[pa]) * 2; break; } if (a[pa + 1] <= b[pb]) { pa++; continue; } LL res1 = a[pa + 1] - a[pa]; res1 = min(res1, (a[pa + 1] - b[pb]) * 2); if (b[pb + 1] <= a[pa + 1]) { res1 = min(res1, (b[pb] - a[pa]) * 2 + (a[pa + 1] - b[pb + 1]) * 2); } else res1 = min(res1, (b[pb] - a[pa]) * 2); int pos1 = lower_bound(b + 1, b + 1 + m, a[pa]) - b; int pos2 = upper_bound(b + 1, b + 1 + m, a[pa + 1]) - b; res1 = min(res1, (b[pos2 - 1] - a[pa]) * 2); pos2 -= 2; // cout << dis[2] << endl; // cout << ask(pos1, pos2, root) << endl; LL res3 = 2 * ask(pos1, pos2, root) + 2 * (a[pa + 1] - a[pa]); // cout << res3 << endl; sumTime += min(res1, res3); pa++; while (pb <= m && b[pb] <= a[pa]) pb++; } cout << sumTime << endl; } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif work(); return 0; }
F:
G:倒序模擬,一開始找1所在的位置pos, 設1喜歡的人是y[pos],然后就相當於找y[pos]那個人的名字,也是倒序模擬,直到找不到了,就直接輸出那個人的名字就ok
H:能證明的是,首先找到一個最大的數字val,在row,col中,這個數字是必定刪除的,然后試試刪除row,或者刪除col,4種情況試一試就好。

#include <bits/stdc++.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; typedef pair<int, int> pii; const int maxn = 1e3 + 20; int a[maxn][maxn]; int n, m; pii findMax(int delRow, int delCol) { int mx = -1, row = -1, col = -1; for (int i = 1; i <= n; ++i) { if (i == delRow) continue; for (int j = 1; j <= m; ++j) { if (j == delCol) continue; if (mx < a[i][j]) { mx = a[i][j]; row = i; col = j; } } } return make_pair(row, col); } vector< pair<pii, int> >vc; int ansMx = inf; void dfs(int row, int col, int delRow, int delCol) { pii res = findMax(delRow, delCol); if (!row && !col) { vc.push_back(make_pair(make_pair(delRow, delCol), a[res.first][res.second])); if (ansMx > a[res.first][res.second]) { ansMx = a[res.first][res.second]; } return; } if (row) { dfs(row - 1, col, res.first, delCol); } if (col) { dfs(row, col - 1, delRow, res.second); } } void work() { cin >> n >> m; for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { cin >> a[i][j]; } } dfs(1, 1, 0, 0); for (int i = 0; i < vc.size(); ++i) { if (vc[i].second == ansMx) { cout << vc[i].first.first << " " << vc[i].first.second << endl; return; } } } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif IOS; work(); return 0; }
I:這是一題神奇的題,其實這個東西我應該算學過,但是它換去矩陣了,所以就轉不過來,思路是隨機生成一個矩陣[1 X n]的矩陣,那么有rand * a * b = rand * c,這些復雜度才O(n^2),多隨機幾個,概率就滿足了。這有點像那些米勒測試啊。

#include <bits/stdc++.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; const int maxn = 1e3 + 2; struct Matrix { int a[maxn][maxn]; int row; int col; bool operator != (struct Matrix& rhs) const { for (int i = 1; i <= col; ++i) { if (a[1][i] != rhs.a[1][i]) return true; } return false; } }ans[4], c, cmp; struct Matrix matrix_mul(struct Matrix a, struct Matrix b, int MOD) { //求解矩陣a*b%MOD // struct Matrix c = {0}; //這個要多次用到,棧分配問題,maxn不能開太大, //LL的時候更加是,空間是maxn*maxn的,這樣時間用得很多,4和5相差300ms c.row = a.row; //行等於第一個矩陣的行 c.col = b.col; //列等於第二個矩陣的列 for (int i = 1; i <= c.row; ++i) for (int j = 1; j <= c.col; ++j) c.a[i][j] = 0; for (register int i = 1; i <= a.row; ++i) { for (register int k = 1; k <= a.col; ++k) { if (a.a[i][k]) { //應付稀疏矩陣,0就不用枚舉下面了 for (register int j = 1; j <= b.col; ++j) { c.a[i][j] = (c.a[i][j] + 1LL * a.a[i][k] * b.a[k][j]) % MOD; } } } } return c; } void work() { srand((time(NULL))); int n; scanf("%d", &n); for (int i = 1; i <= 3; ++i) { ans[i].row = ans[i].col = n; for (int j = 1; j <= n; ++j) { for (int k = 1; k <= n; ++k) { scanf("%d", &ans[i].a[j][k]); } } } cmp.row = 1, cmp.col = n; // cout << RAND_MAX << endl; for (int i = 1; i <= 25; ++i) { int upDate = rand(); for (int k = 1; k <= n; ++k) { cmp.a[1][k] = rand() % 13131 + upDate; } Matrix res1 = matrix_mul(cmp, ans[1], 1e9 + 7); res1 = matrix_mul(res1, ans[2], 1e9 + 7); Matrix res2 = matrix_mul(cmp, ans[3], 1e9 + 7); if (res1 != res2) { printf("NO\n"); return; } } printf("YES\n"); } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif work(); return 0; }
J:
K:
L:
M:簽到題,模擬即可。一個人優先殺最后那個。