A
结论题,手玩一下可以知道,假设攻击a次,恢复b次,且a<=b+1,那么攻击、恢复、攻击、恢复...这样组成的等差数列为区间左端点,求和得出
,恢复、恢复、恢复...攻击、攻击、攻击...这样可以构成区间右端点,求和得出
,那么区间什么时候可以合并?假设攻击次数为a-1,当且仅当
,而且a<=b+1,结合可以得出a>=4且b>=3时,组成连续的一段区间,现在只需要特判b==1和b==2的情况,手算一下可知b==1时3取不到,b==2时8取不到
AC代码:
#include <bits/stdc++.h> using namespace std; using LL = long long; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); LL n, m; int k; cin >> n >> m >> k; n = min(n, m + 1); LL minn = 1; LL maxx = n * (m + 1) + n * (n - 1) / 2; for (int i = 0; i < k; i++) { LL x; cin >> x; if (m == 1 and x == 3 or m == 2 and x == 8) { cout << "NO\n"; continue; } if (x >= minn and x <= maxx) { cout << "YES\n"; } else { cout << "NO\n"; } } return 0; }
B
B题1操作就是加边,让图连通块更大,2操作就是一个连通块里所有点权+1,那这样就可以有个贪心的思想,就是一个连通块需要加的次数就是所有数值中的最大值(这应该很容易理解),那么我们就可以考虑先将所有的值都加起来,一会操作的时候再减去小的,在输入边的时候我们应该存储小的点权,因为我们一开始已经把所有点的点权都加起来了,我们下一步操作就是减去连通块中点权较小的,然后再贪心一下,我们应优先去减去点权较小的中的较大者,然后就是开心的用并查集连通每一个点形成连通块了,因为会有什么重边和自环,而且操作只有min(5n,m),所以每次操作都是很珍贵的,所以只有有效的连边操作才是算到操作里的,至于可能用不着那么多次数,那重边和自环随便怎么弄都对结果没有影响
AC代码:
#include <bits/stdc++.h> using namespace std; using LL = long long; struct node { int u, v; LL height; bool operator <(const node &a) { return a.height < height; } }e[5000010]; int a[500010], n, m, fa[500010]; LL sum; int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n >> m; for (int i = 1; i <= n; i++) { cin >> a[i]; sum += a[i]; fa[i] = i; } for (int i = 0; i < m; i++) { int u, v; cin >> u >> v; e[i].u = u; e[i].v = v; e[i].height = min(a[u], a[v]); } sort(e, e + m); int cnt = min(5 * n, m); for (int i = 0; i < m; i++) { if (cnt == 0) { break; } function<int(int)> getfa = [&](int x) { return x == fa[x] ? x : fa[x] = getfa(fa[x]); }; int a = getfa(e[i].u), b = getfa(e[i].v); if (a != b) { fa[a] = b; sum -= e[i].height; cnt--; } } cout << sum << '\n'; return 0; }
C
贪心,能杀就杀,不能杀就休息,签到题
AC代码:
#pragma GCC optimize(2) #pragma GCC optimize(3) //#pragma GCC optimize("Ofast") #include <iostream> #include <queue> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cmath> #include <cstring> #include <string> #include <map> #include <vector> #include <set> #include <stack> #include <numeric> #include <iomanip> #define lowbit(x) ((x) & -(x)) using namespace std; const int INF = 0x3f3f3f3f; void solve() { long long x, a, b; cin >> x >> a >> b; string s; cin >> s; long long ans = 0; int len = s.length(); for (int i = 0; i < len; i++) { if (s[i] == '0' || x < a) { x += b; } else { x -= a; ans++; } } cout << ans << endl; return; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int _t = 1; //cin >> _t; while (_t--) { solve(); } return 0; } /* 1 2 */
D
大模拟,首先想出构造方法,找到构造规律,构造方法很多
AC代码:
#include <bits/stdc++.h> using namespace std; using LL = long long; int n; int a[1010][1010]; int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n; int idx = 0; function<void(int, int)> D1 = [&](int x, int y) { for (int i = x; i <= n; i += 3) { for (int j = y; j <= n; j += 2) { a[i][j] = a[i][j + 1] = a[i + 1][j] = ++idx; a[i + 1][j + 1] = a[i + 2][j] = a[i + 2][j + 1] = ++idx; } } }; function<void(int)> D2 = [&](int x) { for (int i = x; i <= n; i++) { if (i & 1) { a[i - 1][1] = a[i][1] = a[i][2] = ++idx; } else { a[i - 1][3] = a[i][2] = a[i][3] = ++idx; } } }; function<void(int, int)> D3 = [&](int x, int y) { for (int j = y; j <= n; j += 3) { a[x][j] = a[x][j + 1] = a[x + 1][j] = ++idx; a[x][j + 2] = a[x + 1][j + 2] = a[x + 1][j + 1] = ++idx; } }; if (n == 1) { cout << "YES\n"; cout << 0 << '\n'; } else if (n % 3 == 0) { cout << "NO\n"; } else if (n % 3 == 1) { idx = 5; a[1][1] = a[1][2] = a[2][1] = 1; a[4][3] = a[4][4] = a[3][4] = 2; a[3][1] = a[3][2] = a[4][2] = 3; a[2][2] = a[2][3] = a[3][3] = 4; a[1][3] = a[1][4] = a[2][4] = 5; D3(1, 5); D3(3, 5); if (n & 1) { D2(5); D1(5, 4); } else { D1(5, 1); } cout << "YES\n"; for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { cout << a[i][j] << " \n"[j == n]; } } } else if (n % 3 == 2) { a[1][1] = a[1][2] = a[2][2] = ++idx; D3(1, 3); if (n & 1) { D2(3); D1(3, 4); } else { D1(3, 1); } cout << "YES\n"; for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { cout << a[i][j] << " \n"[j == n]; } } } return 0; }
E
大体意思就是说先考虑最小值,遍历1到n个点的路径的最小值,考虑不走环直接一个点一个点的走,可知n个点之间只有n-1条边,再考虑最大值就是尽可能的多走环,这时要考虑点的奇偶性,可知如果点的个数是奇数,那么对于完全图来说每个点的出入度之和一定为偶数,这样可以直接构造欧拉回路,而对于点的个数是偶数来说,每个点的出入度之和一定是奇数,那么我们只能留下两个点来作为起始点和终止点,倘若留下一个的话肯定不是最长的,这两个点的出入度之和为奇数,其他点的出入度之和构造成偶数,这样就需要对一些边进行更改方向之类的操作,最终用总边长减去删去的边长就是最长路径
AC代码:
/* Tips: 1.int? long long? 2.don't submit wrong answer 3.figure out logic first, then start writing please 4.know about the range 5.check if you have to input t or not 6.modulo of negative numbers is not a%b, it is a%b + abs(b) */ #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize("Ofast") #include<bits/stdc++.h> using namespace std; #define lowbit(x) ((x) & -(x)) #define endl '\n' #define IOS1 ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr); #define IOS2 ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); typedef vector<int> vi; typedef vector<long long> vll; typedef vector<char> vc; typedef long long ll; template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; } template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; } template<class T> T power(T a, int b) { T res = 1; for (; b; b >>= 1, a = a * a) { if (b & 1) { res = res * a; } } return res; } template <typename T> inline void read(T& x) { x = 0; int f = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); } while (isdigit(ch)) { x = x * 10 + ch - '0', ch = getchar(); } x *= f; } const int INF = 0x3f3f3f3f; const int mod = 1000000007; const double PI = acos(-1.0); const double eps = 1e-6; inline int sgn(double x) { return x < -eps ? -1 : x > eps; } void solve() { long long n, l, r; cin >> n; if (n & 1) { l = n - 1; r = (n * n - n) / 2; } else { l = n - 1; r = (n * n - n) / 2 - n / 2 + 1; } cout << l << " " << r << endl; return; } int main() { IOS1; //IOS2; int __t = 1; // cin >> __t; for (int _t = 1; _t <= __t; _t++) { solve(); } return 0; } /* */
F
AC代码:
/* Tips: 1.int? long long? 2.don't submit wrong answer 3.figure out logic first, then start writing please 4.know about the range 5.check if you have to input t or not 6.modulo of negative numbers is not a%b, it is a%b + abs(b) */ #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize("Ofast") #include<bits/stdc++.h> using namespace std; #define lowbit(x) ((x) & -(x)) #define endl '\n' #define IOS1 ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr); #define IOS2 ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); typedef vector<int> vi; typedef vector<long long> vll; typedef vector<char> vc; typedef long long ll; template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; } template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; } template<class T> T power(T a, int b) { T res = 1; for (; b; b >>= 1, a = a * a) { if (b & 1) { res = res * a; } } return res; } template <typename T> inline void read(T& x) { x = 0; int f = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); } while (isdigit(ch)) { x = x * 10 + ch - '0', ch = getchar(); } x *= f; } const int INF = 0x3f3f3f3f; const int mod = 1000000007; const double PI = acos(-1.0); const double eps = 1e-6; inline int sgn(double x) { return x < -eps ? -1 : x > eps; } const int M = 1000000007; long long a[1000010], f[1000010]; int it = 1; long long res, id[1000010]; long long calc(long long a, long long b) { a += b; return (a >= M) ? a - M : a; } long long ksm(long long a, long long b) { long long ans = 1; for (; b; b >>= 1, a = a * a % M) { if (b & 1) { ans = ans * a % M; } } return ans % M; } void solve() { int n, t; string s; cin >> n >> t >> s; s = 'X' + s; for (int i = 1; i <= n; i++) { cin >> a[i]; f[i] = 1; } for (int i = 1; i <= n; i++) { f[it] = f[it] * a[i] % M; id[i] = it; if (s[i] == '+') { it++; } } for (int i = 1; i <= it; i++) { res = calc(res, f[i]); } while (t--) { int i, j; cin >> i >> j; res = calc(res, M - f[id[i]]); f[id[i]] = f[id[i]] * ksm(a[i], M - 2) % M; f[id[i]] = f[id[i]] * j % M; a[i] = j; res = calc(res, f[id[i]]); cout << res << endl; } return; } int main() { IOS1; //IOS2; int __t = 1; // cin >> __t; for (int _t = 1; _t <= __t; _t++) { solve(); } return 0; } /* */
G
考虑LCA以及树上差分,先求一下每条由上到下以及由下到上的路径点权和,那么总的体力就是起点的高度+从u到lca(u,v)的消耗的和+从v到lca(u,v)的消耗的和,注意就是从低跳到高消耗体力,而从高跳到低不消耗体力,所以如果两点的差为负数应置为0,注意不要都开long long,否则MLE等着你
AC代码:
#include <bits/stdc++.h> using namespace std; using LL = long long; int n, m; int a[1000010], f[1000010][21], dep[1000010]; LL sum1[1000010], sum2[1000010]; vector<LL> G[1000010]; void dfs(int u, int fa) { dep[u] = dep[fa] + 1; f[u][0] = fa; sum1[u] = sum1[fa] + max(0ll, a[fa] - a[u]); sum2[u] = sum2[fa] + max(0ll, a[u] - a[fa]); for (int i = 1; (1 << i) < dep[u]; i++) { f[u][i] = f[f[u][i - 1]][i - 1]; } for (auto v : G[u]) { if (v != fa) { dfs(v, u); } } } int lca(int x, int y) { if (dep[x] > dep[y]) { swap(x, y); } for (int i = 20; i >= 0; i--) { if (dep[x] <= dep[y] - (1 << i)) { y = f[y][i]; } } if (x == y) { return x; } for (int i = 20 ; i >= 0; i--) { if (f[x][i] == f[y][i]) { continue; } x = f[x][i]; y = f[y][i]; } return f[x][0]; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n >> m; for (int i = 1; i <= n; i++) { cin >> a[i]; } for (int i = 0; i < n - 1; i++) { int u, v; cin >> u >> v; G[u].push_back(v); G[v].push_back(u); } dfs(1, 0); for (int i = 0; i < m; i++) { int u, v; cin >> u >> v; cout << a[u] + sum1[u] + sum2[v] - sum1[lca(u, v)] - sum2[lca(u, v)] << '\n'; } return 0; }
H
AC代码:
#pragma GCC optimize(2) #pragma GCC optimize(3) //#pragma GCC optimize("Ofast") #include <iostream> #include <queue> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cmath> #include <cstring> #include <string> #include <map> #include <vector> #include <set> #include <stack> #include <numeric> #include <iomanip> #define lowbit(x) ((x) & -(x)) using namespace std; const int INF = 0x3f3f3f3f; const int mod = 1000000007; void solve() { long long n, m; cin >> n >> m; if (m == 0) { cout << 1 << endl; } else { cout << n % mod << endl; } return; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int _t = 1; //cin >> _t; while (_t--) { solve(); } return 0; } /* cn 2; n * n - 1 / 2 */
I
小模拟,考验代码基本功
AC代码:
/* Tips: 1.int? long long? 2.don't submit wrong answer 3.figure out logic first, then start writing please 4.know about the range 5.check if you have to input t or not 6.modulo of negative numbers is not a%b, it is a%b + abs(b) */ #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize("Ofast") #include<bits/stdc++.h> using namespace std; #define lowbit(x) ((x) & -(x)) #define endl '\n' #define IOS1 ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr); #define IOS2 ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); typedef vector<int> vi; typedef vector<long long> vll; typedef vector<char> vc; typedef long long ll; template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; } template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; } template<class T> T power(T a, int b) { T res = 1; for (; b; b >>= 1, a = a * a) { if (b & 1) { res = res * a; } } return res; } template <typename T> inline void read(T& x) { x = 0; int f = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); } while (isdigit(ch)) { x = x * 10 + ch - '0', ch = getchar(); } x *= f; } const int INF = 0x3f3f3f3f; const int mod = 1000000007; const double PI = acos(-1.0); const double eps = 1e-6; inline int sgn(double x) { return x < -eps ? -1 : x > eps; } string s="X\"!'*+-.08:=^_WTYUIOAHXVM|<>\\/[]{}()"; char res[1005000]; void solve() { int n, m; cin >> n >> m; int l = 1, r = n; if (n < m || m > 35) { cout << -1 << endl; return; } if (m > 2 || (((l + 1) == r) && m == 2)) { res[l] = '('; res[r] = ')'; l++; r--; m -= 2; } if (m > 2 || (((l + 1) == r) && m == 2)) { res[l] = '['; res[r] = ']'; l++; r--; m -= 2; } if (m > 2 || (((l + 1) == r) && m == 2)) { res[l] = '{'; res[r] = '}'; l++; r--; m -= 2; } if (m > 2 || (((l + 1) == r) && m == 2)) { res[l] = '\\'; res[r] = '/'; l++; r--; m -= 2; } if (m > 2 || (((l + 1) == r) && m == 2)) { res[l] = '<'; res[r] = '>'; l++; r--; m -= 2; } while (l <= r) { if (m == 0) { res[l] = res[r] = '\"'; } else { res[l] = res[r] = s[m]; m--; } l++; r--; } if (m) { cout << -1; return; } cout << res + 1; return; } int main() { IOS1; //IOS2; int __t = 1; // cin >> __t; for (int _t = 1; _t <= __t; _t++) { solve(); } return 0; } /* */
K
签到题,按题意模拟即可
AC代码:
#pragma GCC optimize(2) #pragma GCC optimize(3) //#pragma GCC optimize("Ofast") #include <iostream> #include <queue> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cmath> #include <cstring> #include <string> #include <map> #include <vector> #include <set> #include <stack> #include <numeric> #include <iomanip> #define lowbit(x) ((x) & -(x)) using namespace std; const int INF = 0x3f3f3f3f; void solve() { vector<int> a(11, 0); string s; cin >> s; int len = s.length(); for (int i = 0; i < len; i++) { if (s[i] != '5') { a[s[i] - '0']++; a[5]++; } } for (int i = 1; i <= 9; i++) { cout << a[i] << " \n"[i == 9]; } return; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int _t = 1; //cin >> _t; while (_t--) { solve(); } return 0; } /* 1 2 */
L
L和M是一个题意只是数据范围不一样,所以直接在这里解释两个题,看到数据最大的那个题优先想到用数据结构去优化它,因此树状数组维护动态前缀和。先按照气运值排序,然后遍历一遍气运,每次求当前点和当前点前
位的区间和,并将该值加入到当前位下标的树状数组中进行更新。最后对 n 进行查询,结果即为要求的方案数
AC代码:
#include <bits/stdc++.h> using namespace std; using LL = long long; namespace GenHelper { int z1,z2,z3,z4,z5,u,res; int get() { z5=((z1<<6)^z1)>>13; z1=((int)(z1&4294967)<<18)^z5; z5=((z2<<2)^z2)>>27; z2=((z2&4294968)<<2)^z5; z5=((z3<<13)^z3)>>21; z3=((z3&4294967)<<7)^z5; z5=((z4<<3)^z4)>>12; z4=((z4&4294967)<<13)^z5; return (z1^z2^z3^z4); } int read(int m) { u=get(); u>>=1; if(m==0)res=u; else res=(u/2345+1000054321)%m; return res; } void srand(int x) { z1=x; z2=(~x)^(0x23333333); z3=x^(0x12345798); z4=(~x)+51; u = 0; } } using namespace GenHelper; using namespace std; const int N=2e6+7,mod=1e9+7; int a[N],b[N]; struct node { int x, id; bool operator <(const node &a) { if (a.x != x) { return x < a.x; } return id < a.id; } }s[N]; LL tree[N]; void add(int x, int y) { for (int i = y; i < N; i += i & (-i)) { tree[i] = (tree[i] + x) % mod; } } LL ask(int x) { LL res = 0; while (x) { res = (res + tree[x]) % mod; x -= x & (-x); } return res % mod; } int main(){ int n,seed; scanf("%d %d",&n,&seed); srand(seed); for(int i=1;i<=n;i++){ a[i]=read(0),b[i]=read(i); s[i].id = i; s[i].x = a[i]; } sort(s + 1, s + 1 + n); for (int i = 1; i <= n; i++) { LL x = (ask(s[i].id - 1) - ask(s[i].id - 1 - b[s[i].id]) + 1 + mod) % mod; add(x, s[i].id); } cout << ask(n) << '\n'; return 0; }
M
AC代码:
#include <bits/stdc++.h> using namespace std; using LL = long long; namespace GenHelper { int z1,z2,z3,z4,z5,u,res; int get() { z5=((z1<<6)^z1)>>13; z1=((int)(z1&4294967)<<18)^z5; z5=((z2<<2)^z2)>>27; z2=((z2&4294968)<<2)^z5; z5=((z3<<13)^z3)>>21; z3=((z3&4294967)<<7)^z5; z5=((z4<<3)^z4)>>12; z4=((z4&4294967)<<13)^z5; return (z1^z2^z3^z4); } int read(int m) { u=get(); u>>=1; if(m==0)res=u; else res=(u/2345+1000054321)%m; return res; } void srand(int x) { z1=x; z2=(~x)^(0x23333333); z3=x^(0x12345798); z4=(~x)+51; u = 0; } } using namespace GenHelper; using namespace std; const int N=2e6+7,mod=1e9+7; int a[N],b[N]; struct node { int x, id; bool operator <(const node &a) { if (a.x != x) { return x < a.x; } return id < a.id; } }s[N]; LL tree[N]; void add(int x, int y) { for (int i = y; i < N; i += i & (-i)) { tree[i] = (tree[i] + x) % mod; } } LL ask(int x) { LL res = 0; while (x) { res = (res + tree[x]) % mod; x -= x & (-x); } return res % mod; } int main(){ int n,seed; scanf("%d %d",&n,&seed); srand(seed); for(int i=1;i<=n;i++){ a[i]=read(0),b[i]=read(i); s[i].id = i; s[i].x = a[i]; } sort(s + 1, s + 1 + n); for (int i = 1; i <= n; i++) { LL x = (ask(s[i].id - 1) - ask(s[i].id - 1 - b[s[i].id]) + 1 + mod) % mod; add(x, s[i].id); } cout << ask(n) << '\n'; return 0; }
2022牛客寒假算法基础集训营2(12/13)
于 2022-02-15 14:22:25 首次发布