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 "); return; } } // printf("%d %d %d %d ", beOne, enOne, beTwo, enTwo); printf("YES "); if (!beOne && !beTwo) { for (int i = 'a'; i <= 'z'; ++i) { if (pos[i].size() >= 2) { printf("%d %d ", pos[i][0], pos[i][1]); return; } } printf("1 %d ", lenstr); return; } if (!beTwo) beTwo = 1; while (str[beTwo] == str[beOne]) beTwo++; printf("%d %d ", 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 "); else printf("NO "); } 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 "); return; } } printf("YES "); } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif work(); return 0; }
J:
K:
L:
M:签到题,模拟即可。一个人优先杀最后那个。