西北大学2019春季校赛题解简录
提交传送门,密码:jwjtxdy(鸡尾酒天下第一)
A.二分答案,里面用队列模拟。
1 #pragma comment(linker, "/STACK:1024000000,1024000000") 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <ctime> 7 #include <cctype> 8 #include <climits> 9 #include <iostream> 10 #include <iomanip> 11 #include <algorithm> 12 #include <string> 13 #include <sstream> 14 #include <stack> 15 #include <queue> 16 #include <set> 17 #include <map> 18 #include <vector> 19 #include <list> 20 #include <fstream> 21 #include <bitset> 22 #define init(a, b) memset(a, b, sizeof(a)) 23 #define rep(i, a, b) for (int i = a; i <= b; i++) 24 #define irep(i, a, b) for (int i = a; i >= b; i--) 25 using namespace std; 26 27 typedef double db; 28 typedef long long ll; 29 typedef unsigned long long ull; 30 typedef pair<int, int> P; 31 const int inf = 0x3f3f3f3f; 32 const ll INF = 1e18; 33 34 template <typename T> void read(T &x) { 35 x = 0; 36 int s = 1, c = getchar(); 37 for (; !isdigit(c); c = getchar()) 38 if (c == '-') s = -1; 39 for (; isdigit(c); c = getchar()) 40 x = x * 10 + c - 48; 41 x *= s; 42 } 43 44 template <typename T> void write(T x) { 45 if (x < 0) x = -x, putchar('-'); 46 if (x > 9) write(x / 10); 47 putchar(x % 10 + '0'); 48 } 49 50 template <typename T> void writeln(T x) { 51 write(x); 52 puts(""); 53 } 54 55 const int maxn = 2e5 + 5; 56 int n, m, t, d; 57 ll sum[maxn]; 58 P p[maxn]; 59 60 bool ok(int cnt) { 61 init(sum, 0); 62 queue<int> Q; 63 rep(i, 1, n) { 64 while (!Q.empty() && Q.front() + t <= p[i].first) { 65 Q.pop(); 66 cnt++; 67 } 68 if (!cnt) { 69 sum[p[i].second] += Q.front() + t - p[i].first; 70 cnt++; 71 Q.push(Q.front() + t); 72 Q.pop(); 73 } else Q.push(p[i].first); 74 cnt--; 75 } 76 rep(i, 1, m) if (sum[i] >= d) return false; 77 return true; 78 } 79 80 int main() { 81 read(n), read(m), read(t), read(d); 82 if (!n || !m) { 83 puts("0"); 84 return 0; 85 } 86 rep(i, 1, n) read(p[i].first), read(p[i].second); 87 sort(p + 1, p + 1 + n); 88 int l = 1, r = n, ans = 0; 89 while (l < r) { 90 int mid = (l + r) >> 1; 91 if (ok(mid)) { 92 ans = mid; 93 r = mid; 94 } else l = mid + 1; 95 } 96 if (ok(r)) ans = r; 97 writeln(ans); 98 return 0; 99 }
B.因为最后一定会有一个差为m的上下界,枚举下界,然后里面列一列式子发现为了数学算出结果,之前用前缀和预处理一下。
1 #pragma comment(linker, "/STACK:1024000000,1024000000") 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <ctime> 7 #include <cctype> 8 #include <climits> 9 #include <iostream> 10 #include <iomanip> 11 #include <algorithm> 12 #include <string> 13 #include <sstream> 14 #include <stack> 15 #include <queue> 16 #include <set> 17 #include <map> 18 #include <vector> 19 #include <list> 20 #include <fstream> 21 #include <bitset> 22 #define init(a, b) memset(a, b, sizeof(a)) 23 #define rep(i, a, b) for (int i = a; i <= b; i++) 24 #define irep(i, a, b) for (int i = a; i >= b; i--) 25 using namespace std; 26 27 typedef double db; 28 typedef long long ll; 29 typedef unsigned long long ull; 30 typedef pair<int, int> P; 31 const int inf = 0x3f3f3f3f; 32 const ll INF = 1e18; 33 34 template <typename T> void read(T &x) { 35 x = 0; 36 int s = 1, c = getchar(); 37 for (; !isdigit(c); c = getchar()) 38 if (c == '-') s = -1; 39 for (; isdigit(c); c = getchar()) 40 x = x * 10 + c - 48; 41 x *= s; 42 } 43 44 template <typename T> void write(T x) { 45 if (x < 0) x = -x, putchar('-'); 46 if (x > 9) write(x / 10); 47 putchar(x % 10 + '0'); 48 } 49 50 template <typename T> void writeln(T x) { 51 write(x); 52 puts(""); 53 } 54 55 const int maxn = 2e5 + 5; 56 int n, m, a[maxn]; 57 ll sum1[maxn], sum2[maxn], ans = INF; 58 59 inline ll sqr(int a) { return (ll)a * a; } 60 61 inline ll calc(int tmp) { 62 ll ret = 0; 63 int low = lower_bound(a + 1, a + 1 + n, tmp) - a - 1; 64 int high = upper_bound(a + 1, a + 1 + n, tmp + m) - a - 1; 65 ret += sqr(tmp) * low + sum2[low] - (ll)2 * tmp * sum1[low]; 66 ret += sqr(tmp + m) * (n - high) + sum2[n] - sum2[high] - (ll)2 * (tmp + m) * (sum1[n] - sum1[high]); 67 return ret; 68 } 69 70 int main() { 71 read(n), read(m); 72 rep(i, 1, n) read(a[i]); 73 sort(a + 1, a + 1 + n); 74 rep(i, 1, n) { 75 sum1[i] = sum1[i - 1] + a[i]; 76 sum2[i] = sum2[i - 1] + sqr(a[i]); 77 } 78 for (int i = 0; i + m <= maxn - 5; i++) 79 ans = min(ans, calc(i)); 80 writeln(ans); 81 return 0; 82 }
C.毒瘤模拟,我要了数据才过去呜呜。
OX.
OOX
X..
这个数据可以hack一些AC代码,会发现用X去堵住O以后他双杀……我这份也能hack但是我实在懒得改233
1 #include <cstdio> 2 #include <cstring> 3 4 int chess[4][4], B, W; 5 6 int main() { 7 for (int i = 1; i <= 3; i++) { 8 for (int j = 1; j <= 3; j++) { 9 char c = getchar(); 10 if (c == 'X') chess[i][j] = 10, B++; 11 else if (c == 'O') chess[i][j] = -10, W++; 12 else chess[i][j] = -500; 13 } 14 getchar(); 15 } 16 17 auto Go = []() { 18 if (B - W > 1 || W - B > 0) return -2; 19 int tmp3 = 0, tmp4 = 0, numb = 0, numw = 0; 20 bool b1 = false, b2 = false; 21 for (int i = 1; i <= 3; i++) { 22 int tmp1 = 0, tmp2 = 0; 23 for (int j = 1; j <= 3; j++) { 24 tmp1 += chess[i][j]; 25 tmp2 += chess[j][i]; 26 if (i == j) tmp3 += chess[i][j]; 27 if (i + j == 4) tmp4 += chess[i][j]; 28 } 29 if (tmp1 == -30 || tmp2 == -30 || tmp3 == -30 || tmp4 == -30) b1 = true; 30 if (tmp1 == 30 || tmp2 == 30 || tmp3 == 30 || tmp4 == 30) b2 = true; 31 numb += (tmp1 == -480) + (tmp2 == -480) + (tmp3 == -480) + (tmp4 == -480); 32 numw += (tmp1 == -520) + (tmp2 == -520) + (tmp3 == -520) + (tmp4 == -520); 33 } 34 35 if (b1 && b2) return -2; 36 else if (b1) { 37 if (B == W) return -1; 38 else return -2; 39 } 40 else if (b2) { 41 if (B > W) return 1; 42 else return -2; 43 } 44 else { 45 if (B > W) { 46 if (numw > 0) return -1; 47 else if (numb > 1) return 1; 48 else return 0; 49 } else { 50 if (numb > 0) return 1; 51 else if (numw > 1) return -1; 52 else return 0; 53 } 54 } 55 }; 56 57 int flag = Go(); 58 if (flag == -2) puts("impossible"); 59 else if (flag == -1) puts("W"); 60 else if (flag == 0) puts("draw"); 61 else puts("B"); 62 63 return 0; 64 }
D.dp,如果连不上3个以上的话当前这个就是没价值的,所以枚举左边,然后把中间不是这个的都删了算一下。O(n)的做法大概是边走边记录位置然后直接选取最好的?咕咕
1 #include <cstdio> 2 #include <cstring> 3 #define max(a, b) a > b ? a : b 4 5 typedef long long ll; 6 const int maxn = 2050; 7 int n, a[maxn], sec[6], thi[6], num[6][maxn]; 8 ll dp[maxn]; 9 char str[maxn]; 10 11 int main() { 12 scanf("%d", &n); 13 for (int i = 1; i <= 5; ++i) { 14 scanf("%d", &sec[i]); 15 } 16 for (int i = 1; i <= 5; ++i) { 17 scanf("%d", &thi[i]); 18 } 19 scanf("%s", str + 1); 20 for (int i = 1; str[i]; ++i) { 21 a[i] = str[i] - 'A' + 1; 22 } 23 24 for (int i = 1; i <= 5; i++) { 25 for (int j = 1; j <= n; j++) { 26 num[i][j] = num[i][j - 1] + (a[j] == i); 27 } 28 } 29 30 auto calc = [](const int k, const int cnt) { 31 if (cnt < 3) return 0ll; 32 if ((ll)sec[k] * 3 >= thi[k]) return (ll)cnt / 3 * sec[k]; 33 return (ll)thi[k] * (cnt / 9) + (ll)sec[k] * (cnt % 9 / 3); 34 }; 35 for (int i = 1; i <= n; ++i) { 36 for (int j = 1; j <= i; ++j) { 37 if (a[j] == a[i]) { 38 dp[i] = max(dp[i], dp[j - 1] + calc(a[i], num[a[i]][i] - num[a[i]][j - 1])); 39 } 40 } 41 } 42 43 printf("%lld\n", dp[n]); 44 return 0; 45 }
E.可删除并查集。cf上见过类似的。一是操作二如果自己剥离出去自成一派需要新开点;二是加的虚点如果孩子为空了最后扫的时候要删,这两个点WA了我半天。可以像官方题解一样需要的时候再新开点,我一开始就开了n个感觉好丑……
1 #pragma comment(linker, "/STACK:1024000000,1024000000") 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <ctime> 7 #include <cctype> 8 #include <climits> 9 #include <iostream> 10 #include <iomanip> 11 #include <algorithm> 12 #include <string> 13 #include <sstream> 14 #include <stack> 15 #include <queue> 16 #include <set> 17 #include <map> 18 #include <vector> 19 #include <list> 20 #include <fstream> 21 #include <bitset> 22 #define init(a, b) memset(a, b, sizeof(a)) 23 #define rep(i, a, b) for (int i = a; i <= b; i++) 24 #define irep(i, a, b) for (int i = a; i >= b; i--) 25 using namespace std; 26 27 typedef double db; 28 typedef long long ll; 29 typedef unsigned long long ull; 30 typedef pair<int, int> P; 31 const int inf = 0x3f3f3f3f; 32 const ll INF = 1e18; 33 34 template <typename T> void read(T &x) { 35 x = 0; 36 int s = 1, c = getchar(); 37 for (; !isdigit(c); c = getchar()) 38 if (c == '-') s = -1; 39 for (; isdigit(c); c = getchar()) 40 x = x * 10 + c - 48; 41 x *= s; 42 } 43 44 template <typename T> void write(T x) { 45 if (x < 0) x = -x, putchar('-'); 46 if (x > 9) write(x / 10); 47 putchar(x % 10 + '0'); 48 } 49 50 template <typename T> void writeln(T x) { 51 write(x); 52 puts(""); 53 } 54 55 const int maxn = 1e6 + 5; 56 int n, m, ans = -1, f[maxn * 3], cnt[maxn * 3], extra; 57 int u[maxn], v[maxn], tot; 58 bool mark[maxn * 3]; 59 60 inline int fa(int v) { 61 return v == f[v] ? v : f[v] = fa(f[v]); 62 } 63 64 int main() { 65 read(n), read(m); 66 rep(i, 1, n) f[i] = f[n + i] = n + i, cnt[n + i] = 1; 67 rep(i, 1, m) { 68 int op, a, b; 69 read(op); 70 if (op == 1) { 71 read(a), read(b); 72 int t = fa(a), p = fa(b); 73 if (t != p) { 74 cnt[p] += cnt[t]; 75 cnt[t] = 0; 76 f[t] = p; 77 } 78 } else if (op == 2) { 79 read(a), read(b); 80 int t = fa(a), p = fa(b); 81 if (a == b) { 82 cnt[t]--; 83 ++extra; 84 f[a] = f[2 * n + extra] = 2 * n + extra; 85 cnt[f[a]] = 1; 86 } else { 87 f[a] = p; 88 cnt[t]--, cnt[p]++; 89 } 90 } else if (op == 3) { 91 read(a); 92 writeln(cnt[fa(a)] - 1); 93 } else if (op == 4) { 94 read(a), read(b); 95 if (fa(a) == fa(b)) puts("Yes"); 96 else puts("No"); 97 } else { 98 read(a), read(b); 99 u[++tot] = a, v[tot] = b; 100 } 101 } 102 rep(i, 1, tot) { 103 int t = fa(u[i]), p = fa(v[i]); 104 if (t == p) mark[t] = true; 105 } 106 rep(i, 1 + n, n + n + extra) { 107 if (f[i] == i && cnt[i] && !mark[i]) ans = max(ans, cnt[i]); 108 } 109 writeln(ans); 110 return 0; 111 }
Update:改了改新的写法:
1 #pragma comment(linker, "/STACK:1024000000,1024000000") 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <ctime> 7 #include <cctype> 8 #include <climits> 9 #include <iostream> 10 #include <iomanip> 11 #include <algorithm> 12 #include <string> 13 #include <sstream> 14 #include <stack> 15 #include <queue> 16 #include <set> 17 #include <map> 18 #include <vector> 19 #include <list> 20 #include <fstream> 21 #include <bitset> 22 #define init(a, b) memset(a, b, sizeof(a)) 23 #define rep(i, a, b) for (int i = a; i <= b; i++) 24 #define irep(i, a, b) for (int i = a; i >= b; i--) 25 using namespace std; 26 27 typedef double db; 28 typedef long long ll; 29 typedef unsigned long long ull; 30 typedef pair<int, int> P; 31 const int inf = 0x3f3f3f3f; 32 const ll INF = 1e18; 33 34 template <typename T> void read(T &x) { 35 x = 0; 36 int s = 1, c = getchar(); 37 for (; !isdigit(c); c = getchar()) 38 if (c == '-') s = -1; 39 for (; isdigit(c); c = getchar()) 40 x = x * 10 + c - 48; 41 x *= s; 42 } 43 44 template <typename T> void write(T x) { 45 if (x < 0) x = -x, putchar('-'); 46 if (x > 9) write(x / 10); 47 putchar(x % 10 + '0'); 48 } 49 50 template <typename T> void writeln(T x) { 51 write(x); 52 puts(""); 53 } 54 55 const int maxn = 1e6 + 5; 56 int n, m, ans = -1, f[maxn * 2], New[maxn * 2], cnt[maxn * 2], extra; 57 int u[maxn], v[maxn], tot; 58 bool mark[maxn * 2]; 59 60 inline int fa(int v) { 61 return v == f[v] ? v : f[v] = fa(f[v]); 62 } 63 64 int main() { 65 read(n), read(m); 66 extra = n; 67 rep(i, 1, n) f[i] = New[i] = i, cnt[i] = 1; 68 rep(i, 1, m) { 69 int op, a, b; 70 read(op); 71 if (op == 1) { 72 read(a), read(b); 73 int t = fa(New[a]), p = fa(New[b]); 74 if (t != p) { 75 cnt[p] += cnt[t]; 76 cnt[t] = 0; 77 f[t] = p; 78 } 79 } else if (op == 2) { 80 read(a), read(b); 81 int t = fa(New[a]), p = fa(New[b]); 82 cnt[t]--; 83 New[a] = ++extra; 84 f[New[a]] = extra; 85 if (a != b) { 86 f[p] = extra; 87 cnt[extra] += cnt[p] + 1; 88 cnt[p] = 0; 89 } else cnt[extra] = 1; 90 } else if (op == 3) { 91 read(a); 92 writeln(cnt[fa(New[a])] - 1); 93 } else if (op == 4) { 94 read(a), read(b); 95 if (fa(New[a]) == fa(New[b])) puts("Yes"); 96 else puts("No"); 97 } else { 98 read(a), read(b); 99 u[++tot] = a, v[tot] = b; 100 } 101 } 102 rep(i, 1, tot) { 103 int t = fa(New[u[i]]), p = fa(New[v[i]]); 104 if (t == p) mark[t] = true; 105 } 106 rep(i, 1, extra) { 107 if (f[i] == i && cnt[i] && !mark[i]) ans = max(ans, cnt[i]); 108 } 109 writeln(ans); 110 return 0; 111 }
F.暴力求字典序,方法是深搜试填,如果当前填的小于串里这个位置本来的字符,则后面的直接用组合数算出来。
1 #pragma comment(linker, "/STACK:1024000000,1024000000") 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <ctime> 7 #include <cctype> 8 #include <climits> 9 #include <iostream> 10 #include <iomanip> 11 #include <algorithm> 12 #include <string> 13 #include <sstream> 14 #include <stack> 15 #include <queue> 16 #include <set> 17 #include <map> 18 #include <vector> 19 #include <list> 20 #include <fstream> 21 #include <bitset> 22 #define init(a, b) memset(a, b, sizeof(a)) 23 #define rep(i, a, b) for (int i = a; i <= b; i++) 24 #define irep(i, a, b) for (int i = a; i >= b; i--) 25 using namespace std; 26 27 typedef double db; 28 typedef long long ll; 29 typedef unsigned long long ull; 30 typedef pair<int, int> P; 31 const int inf = 0x3f3f3f3f; 32 const ll INF = 1e18; 33 34 template <typename T> void read(T &x) { 35 x = 0; 36 int s = 1, c = getchar(); 37 for (; !isdigit(c); c = getchar()) 38 if (c == '-') s = -1; 39 for (; isdigit(c); c = getchar()) 40 x = x * 10 + c - 48; 41 x *= s; 42 } 43 44 template <typename T> void write(T x) { 45 if (x < 0) x = -x, putchar('-'); 46 if (x > 9) write(x / 10); 47 putchar(x % 10 + '0'); 48 } 49 50 template <typename T> void writeln(T x) { 51 write(x); 52 puts(""); 53 } 54 55 const int maxn = 2e4 + 5; 56 const int mod = 1e9 + 7; 57 int n, num[maxn]; 58 ll fac[maxn], finv[maxn]; 59 string s, t, str; 60 61 ll ksm(ll a, int b) { 62 ll ret = 1; 63 for (; b; b >>= 1) { 64 if (b & 1) ret = ret * a % mod; 65 a = a * a % mod; 66 } 67 return ret; 68 } 69 70 void pre() { 71 fac[0] = finv[0] = 1; 72 rep(i, 1, n) fac[i] = fac[i - 1] * i % mod; 73 finv[n] = ksm(fac[n], mod - 2); 74 irep(i, n - 1, 1) finv[i] = finv[i + 1] * (i + 1) % mod; 75 } 76 77 ll C(int n, int m) { 78 return fac[n] * finv[n - m] % mod * finv[m] % mod; 79 } 80 81 int dfs(int pos, int ch) { 82 if (pos == n - 1) return 0; 83 if (pos >= 0 && str[pos] - 'A' > ch) { 84 int sum = n - 1 - pos; 85 ll ret = 1ll; 86 for (int i = 0; i < 26; ++i) { 87 if (num[i]) { 88 ret = (ret * C(sum, num[i])) % mod; 89 sum -= num[i]; 90 } 91 } 92 return ret; 93 } 94 95 ll tmp = 0ll; 96 for (int i = 0; i < 26; ++i) { 97 if (i <= str[pos + 1] - 'A' && num[i]) { 98 num[i]--; 99 tmp = (tmp + dfs(pos + 1, i)) % mod; 100 num[i]++; 101 } 102 } 103 return tmp; 104 } 105 106 ll calc(string tmp) { 107 str = tmp; 108 init(num, 0); 109 for (char i : str) 110 num[i - 'A']++; 111 return dfs(-1, 30); 112 } 113 114 int main() { 115 cin >> n >> s >> t; 116 pre(); 117 cout << (calc(s) - calc(t) + mod) % mod << endl; 118 return 0; 119 }
G.裸最短路,点权+边权。
1 #pragma comment(linker, "/STACK:1024000000,1024000000") 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <ctime> 7 #include <cctype> 8 #include <climits> 9 #include <iostream> 10 #include <iomanip> 11 #include <algorithm> 12 #include <string> 13 #include <sstream> 14 #include <stack> 15 #include <queue> 16 #include <set> 17 #include <map> 18 #include <vector> 19 #include <list> 20 #include <fstream> 21 #include <bitset> 22 #define init(a, b) memset(a, b, sizeof(a)) 23 #define rep(i, a, b) for (int i = a; i <= b; i++) 24 #define irep(i, a, b) for (int i = a; i >= b; i--) 25 using namespace std; 26 27 typedef double db; 28 typedef long long ll; 29 typedef unsigned long long ull; 30 typedef pair<ll, int> P; 31 const int inf = 0x3f3f3f3f; 32 const ll INF = 1e18; 33 34 template <typename T> void read(T &x) { 35 x = 0; 36 int s = 1, c = getchar(); 37 for (; !isdigit(c); c = getchar()) 38 if (c == '-') s = -1; 39 for (; isdigit(c); c = getchar()) 40 x = x * 10 + c - 48; 41 x *= s; 42 } 43 44 template <typename T> void write(T x) { 45 if (x < 0) x = -x, putchar('-'); 46 if (x > 9) write(x / 10); 47 putchar(x % 10 + '0'); 48 } 49 50 template <typename T> void writeln(T x) { 51 write(x); 52 puts(""); 53 } 54 55 const int maxn = 2e5 + 5; 56 vector<int> factor[maxn]; 57 vector<P> Edge[maxn]; 58 int n; 59 ll dis[maxn], a[maxn]; 60 61 inline void pre() { 62 rep(i, 1, maxn - 5) { 63 for (int j = i; j <= maxn - 5; j += i) { 64 factor[j].push_back(i); 65 } 66 } 67 } 68 69 ll dij() { 70 dis[1] = a[1]; 71 rep(i, 2, n) dis[i] = INF; 72 priority_queue<P, vector<P>, greater<P>> Q; 73 Q.push(P(a[1], 1)); 74 while (!Q.empty()) { 75 ll d = Q.top().first; 76 int p = Q.top().second; 77 Q.pop(); 78 if (dis[p] < d) continue; 79 for (P to : Edge[p]) { 80 if (dis[to.second] > dis[p] + to.first + a[to.second]) { 81 dis[to.second] = dis[p] + to.first + a[to.second]; 82 Q.push(P(dis[to.second], to.second)); 83 } 84 } 85 } 86 return dis[n] == INF ? -1 : dis[n]; 87 } 88 89 int main() { 90 read(n); 91 pre(); 92 rep(i, 1, n) { 93 ll b, c, d; 94 read(a[i]), read(b), read(c), read(d); 95 for (int j : factor[c]) { 96 if (i + j <= n) { 97 Edge[i].push_back(P(b, i + j)); 98 } else break; 99 } 100 if (i != d) Edge[i].push_back(P(0, d)); 101 } 102 cout << dij() << endl; 103 return 0; 104 }
H.思维题。m < n时,对于n个数求前缀和也是n个数,都%m以后必有两相同的,则中间的这段就是可以整除m的;m == n时有可能没有两个相同的,但这时就会必有0,则这段前缀和为答案。所以直接输出Yes即可。
1 #include <cstdio> 2 3 int main() { 4 puts("Yes"); 5 return 0; 6 }
I.一眼看过去期望dp套路题,然后莽WA了……要最坏排列所以先贪心排序一波。然鹅改完虽然A过去了,好像所有人中只有我不会正着推用了毒瘤的倒推写法?题解怎么一句话就推完了Orz……如果按照gay论课讲的那个几何分布的话好像还蛮有道理?设dp[i]为成功i个的期望步数,如果从i-1成功到达i的概率为p,则dp[i] = (dp[i-1] + 1) / p。
1 #pragma comment(linker, "/STACK:1024000000,1024000000") 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <ctime> 7 #include <cctype> 8 #include <climits> 9 #include <iostream> 10 #include <iomanip> 11 #include <algorithm> 12 #include <string> 13 #include <sstream> 14 #include <stack> 15 #include <queue> 16 #include <set> 17 #include <map> 18 #include <vector> 19 #include <list> 20 #include <fstream> 21 #include <bitset> 22 #define init(a, b) memset(a, b, sizeof(a)) 23 #define rep(i, a, b) for (int i = a; i <= b; i++) 24 #define irep(i, a, b) for (int i = a; i >= b; i--) 25 using namespace std; 26 27 typedef double db; 28 typedef long long ll; 29 typedef unsigned long long ull; 30 typedef pair<int, int> P; 31 const int inf = 0x3f3f3f3f; 32 const ll INF = 1e18; 33 34 template <typename T> void read(T &x) { 35 x = 0; 36 int s = 1, c = getchar(); 37 for (; !isdigit(c); c = getchar()) 38 if (c == '-') s = -1; 39 for (; isdigit(c); c = getchar()) 40 x = x * 10 + c - 48; 41 x *= s; 42 } 43 44 template <typename T> void write(T x) { 45 if (x < 0) x = -x, putchar('-'); 46 if (x > 9) write(x / 10); 47 putchar(x % 10 + '0'); 48 } 49 50 template <typename T> void writeln(T x) { 51 write(x); 52 puts(""); 53 } 54 55 const int maxn = 1e5 + 5; 56 const int mod = 1e9 + 7; 57 int n; 58 struct pai { 59 int a, b; 60 bool operator < (const pai& rhs) const { 61 return (db)a / b > (db)rhs.a / rhs.b; 62 } 63 }t[maxn]; 64 int p[maxn], q[maxn]; 65 int A[maxn], B[maxn]; 66 67 inline int ksm(int a, int b) { 68 int res = 1; 69 for (; b; b >>= 1) { 70 if (b & 1) res = (ll)res * a % mod; 71 a = (ll)a * a % mod; 72 } 73 return res; 74 } 75 76 int main() { 77 read(n); 78 rep(i, 0, n - 1) { 79 read(t[i].a); 80 read(t[i].b); 81 } 82 sort(t, t + n); 83 rep(i, 0, n - 1) { 84 int a = t[i].a, b = t[i].b; 85 p[i] = (ll)a * ksm(b, mod - 2) % mod; 86 q[i] = (1 - p[i] + mod) % mod; 87 } 88 89 irep(i, n - 1, 0) { 90 A[i] = ((ll)p[i] * A[i + 1] % mod + q[i]) % mod; 91 B[i] = ((ll)p[i] * B[i + 1] + 1) % mod; 92 } 93 writeln((ll)B[0] * ksm((1 - A[0] + mod) % mod, mod - 2) % mod); 94 return 0; 95 }
J.线段树维护一下即可。为了能用线段树维护……使用bfs序一下,这样可以p和p的父亲单点修改,p的孩子因为bfs所以都挨着,修改一下这个区间。可以说一说的是val & (val - 1)本质上就是把lowbit减掉,log次操作就归零了,但这道题里好像没用,而且基本上只能暴力修改,不是区间数字都一样的话没法懒标记。然后就是懒标记tag,因为修改值的操作是直接修改成数字所以tag就直接记录这个数字即可,而同时起到一个bool的作用,如果不是-1的话说明这个区间数字都相同,可以迅速修改。
码量稍大,但思维直观。
1 #pragma comment(linker, "/STACK:1024000000,1024000000") 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <ctime> 7 #include <cctype> 8 #include <climits> 9 #include <iostream> 10 #include <iomanip> 11 #include <algorithm> 12 #include <string> 13 #include <sstream> 14 #include <stack> 15 #include <queue> 16 #include <set> 17 #include <map> 18 #include <vector> 19 #include <list> 20 #include <fstream> 21 #include <bitset> 22 #define init(a, b) memset(a, b, sizeof(a)) 23 #define rep(i, a, b) for (int i = a; i <= b; i++) 24 #define irep(i, a, b) for (int i = a; i >= b; i--) 25 using namespace std; 26 27 typedef double db; 28 typedef long long ll; 29 typedef unsigned long long ull; 30 typedef pair<int, int> P; 31 const int inf = 0x3f3f3f3f; 32 const ll INF = 1e18; 33 34 template <typename T> void read(T &x) { 35 x = 0; 36 int s = 1, c = getchar(); 37 for (; !isdigit(c); c = getchar()) 38 if (c == '-') s = -1; 39 for (; isdigit(c); c = getchar()) 40 x = x * 10 + c - 48; 41 x *= s; 42 } 43 44 template <typename T> void write(T x) { 45 if (x < 0) x = -x, putchar('-'); 46 if (x > 9) write(x / 10); 47 putchar(x % 10 + '0'); 48 } 49 50 template <typename T> void writeln(T x) { 51 write(x); 52 puts(""); 53 } 54 55 const int maxn = 2e5 + 10; 56 int n, m, val[maxn]; 57 int l[maxn], r[maxn], f[maxn], bfn[maxn], mp[maxn], cnt; 58 vector<int> Edge[maxn]; 59 60 class SegmentTree { 61 public: 62 #define ls(p) p << 1 63 #define rs(p) p << 1 | 1 64 65 struct Node { 66 int l, r; 67 ll sum, tag; 68 69 void ud1() { 70 tag &= tag - 1; 71 sum = tag * (r - l + 1); 72 } 73 74 void ud2(ll x) { 75 tag = x; 76 sum = x * (r - l + 1); 77 } 78 }t[maxn << 2]; 79 80 void Push_Up(int p) { 81 t[p].sum = t[ls(p)].sum + t[rs(p)].sum; 82 t[p].tag = t[ls(p)].tag == t[rs(p)].tag ? t[ls(p)].tag : -1; 83 } 84 85 void Push_Down(int p) { 86 if (t[p].tag >= 0) { 87 t[ls(p)].ud2(t[p].tag); 88 t[rs(p)].ud2(t[p].tag); 89 } 90 } 91 92 void Build(int l, int r, int p) { 93 t[p].l = l, t[p].r = r; 94 if (l == r) { 95 t[p].sum = t[p].tag = val[mp[l]]; 96 return; 97 } 98 int mid = (l + r) >> 1; 99 Build(l, mid, ls(p)); 100 Build(mid + 1, r, rs(p)); 101 Push_Up(p); 102 } 103 104 void Update1(int l, int r, int p) { 105 if (t[p].tag != -1 && l <= t[p].l && t[p].r <= r) { 106 t[p].ud1(); 107 return; 108 } 109 Push_Down(p); 110 int mid = (t[p].l + t[p].r) >> 1; 111 if (l <= mid) Update1(l, r, ls(p)); 112 if (mid < r) Update1(l, r, rs(p)); 113 Push_Up(p); 114 } 115 116 void Update2(int l, int r, int p, int k) { 117 if (l <= t[p].l && t[p].r <= r) { 118 t[p].ud2(k); 119 return; 120 } 121 Push_Down(p); 122 int mid = (t[p].l + t[p].r) >> 1; 123 if (l <= mid) Update2(l, r, ls(p), k); 124 if (mid < r) Update2(l, r, rs(p), k); 125 Push_Up(p); 126 } 127 128 ll Query(int l, int r, int p) { 129 if (l <= t[p].l && t[p].r <= r) { 130 return t[p].sum; 131 } 132 Push_Down(p); 133 int mid = (t[p].l + t[p].r) >> 1; 134 ll ret = 0ll; 135 if (l <= mid) ret += Query(l, r, ls(p)); 136 if (mid < r) ret += Query(l, r, rs(p)); 137 Push_Up(p); 138 return ret; 139 } 140 }T; 141 142 void BFS() { 143 queue<P> Q; 144 Q.push(P(1, 0)); 145 bfn[1] = ++cnt; 146 mp[cnt] = 1; 147 while (!Q.empty()) { 148 int x = Q.front().first, fa = Q.front().second; 149 Q.pop(); 150 l[fa] = min(l[fa], bfn[x]); 151 r[fa] = max(r[fa], bfn[x]); 152 for (int son : Edge[x]) { 153 if (son == fa) continue; 154 bfn[son] = ++cnt; 155 mp[cnt] = son; 156 f[son] = x; 157 l[x] = r[x] = cnt; 158 Q.push(P(son, x)); 159 } 160 } 161 } 162 163 int main() { 164 read(n), read(m); 165 rep(i, 1, n) read(val[i]); 166 rep(i, 1, n - 1) { 167 int u, v; 168 read(u), read(v); 169 Edge[u].push_back(v); 170 Edge[v].push_back(u); 171 } 172 BFS(); 173 T.Build(1, n, 1); 174 rep(i, 1, m) { 175 int op, p; 176 read(op), read(p); 177 if (op == 1) { 178 T.Update1(bfn[p], bfn[p], 1); 179 if (f[p]) T.Update1(bfn[f[p]], bfn[f[p]], 1); 180 if (l[p]) T.Update1(l[p], r[p], 1); 181 } else if (op == 2) { 182 ll x; 183 read(x); 184 T.Update2(bfn[p], bfn[p], 1, x); 185 if (f[p]) T.Update2(bfn[f[p]], bfn[f[p]], 1, x); 186 if (l[p]) T.Update2(l[p], r[p], 1, x); 187 } else { 188 ll Q = T.Query(bfn[p], bfn[p], 1); 189 if (f[p]) Q += T.Query(bfn[f[p]], bfn[f[p]], 1); 190 if (l[p]) Q += T.Query(l[p], r[p], 1); 191 writeln(Q); 192 } 193 } 194 return 0; 195 }
K.1e18逼我猜结论……好吧小数据脑补一下发现是博弈论中常见的对称手法,如果偶数的话鸡尾酒对称着下,否则沃老师占中,然后也对称着下。
1 #include <cstdio> 2 3 long long n, m; 4 5 int main() { 6 scanf("%lld %lld", &n, &m); 7 n = n % 2 * m % 2; 8 puts(n ? "wls" : "cocktail"); 9 return 0; 10 }
L.差分dp,对我来说最难理解的一道题了嘤嘤嘤。官方题解的dp意义并不常规(常规设到达n的最短时间),而是某个时间点能否到达n。这样就不是像往常一样最后输出一下边界,而是发现dp[i][n]为真直接输出。(看其他大佬AC的代码也有设常规dp的,可做。)
想了好久细节的部分,其做法的正确性,比如:
为什么下面需要dp和ok结合判断,输出却不需要ok判断?(注释)
一些边界情况?(比如刚好可达但却来车了:数据:3 1 2 2 5. 这时应输出7,即使到了2也因为来车了不能转移)
dp为真ok却为假这样的情况是否只有那一种?(应该是的吧……就是上面这种。否则如果之前ok就是false,l和r延伸时也不可能延伸到这里,故而dp也不会为真)
加两个虚值的意义以及其值可以随便改吗?(加0时刻才能开始转移;加inf时刻是为了最后时刻的i+1有值可取避免溢出,所以值随便设)
l和r不初始化也不判定是否会导致错误?(不会,因为没有l、r值的会被ok直接筛下去)
等等……
大概当你第一次见到某种精巧的设计之时都会如此懵逼,然而自己还是下次还是设计不出来。
1 #pragma comment(linker, "/STACK:1024000000,1024000000") 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <ctime> 7 #include <cctype> 8 #include <climits> 9 #include <iostream> 10 #include <iomanip> 11 #include <algorithm> 12 #include <string> 13 #include <sstream> 14 #include <stack> 15 #include <queue> 16 #include <set> 17 #include <map> 18 #include <vector> 19 #include <list> 20 #include <fstream> 21 #include <bitset> 22 #define init(a, b) memset(a, b, sizeof(a)) 23 #define rep(i, a, b) for (int i = a; i <= b; i++) 24 #define irep(i, a, b) for (int i = a; i >= b; i--) 25 using namespace std; 26 27 typedef double db; 28 typedef long long ll; 29 typedef unsigned long long ull; 30 typedef pair<int, int> P; 31 const int inf = 0x3f3f3f3f; 32 const ll INF = 1e18; 33 34 template <typename T> void read(T &x) { 35 x = 0; 36 int s = 1, c = getchar(); 37 for (; !isdigit(c); c = getchar()) 38 if (c == '-') s = -1; 39 for (; isdigit(c); c = getchar()) 40 x = x * 10 + c - 48; 41 x *= s; 42 } 43 44 template <typename T> void write(T x) { 45 if (x < 0) x = -x, putchar('-'); 46 if (x > 9) write(x / 10); 47 putchar(x % 10 + '0'); 48 } 49 50 template <typename T> void writeln(T x) { 51 write(x); 52 puts(""); 53 } 54 55 const int maxn = 2e3 + 5; 56 int n, m; 57 pair<int, P> p[maxn << 1]; 58 int dp[maxn << 1][maxn], l[maxn], r[maxn]; 59 bool ok[maxn]; 60 61 int main() { 62 read(n), read(m); 63 rep(i, 1, m) { 64 int a, b, c; 65 read(a), read(b), read(c); 66 p[i * 2 - 1] = make_pair(b, P(a, 0)); 67 p[i * 2] = make_pair(c, P(a, 1)); 68 } 69 p[0] = make_pair(0, P(0, 1)); 70 p[2 * m + 1] = make_pair((int)1e9 + 5, P(0, 1)); 71 sort(p, p + 2 * m + 2); 72 73 memset(ok, true, sizeof ok);//一开始都是ok的 74 dp[0][0] = 1, dp[0][1] = -1; 75 rep(i, 0, 2 * m) { 76 rep(j, 1, n) dp[i][j] += dp[i][j - 1]; 77 if (dp[i][n]) { 78 irep(j, n - 1, 0) if (dp[i - 1][j]) { 79 //dp[i][n]可行一定是dp[i-1][j]转移过来的,下边min和max的操作保证了:dp[i][n]可达时,此处不可能存在dp[i-1][j] > 0 && ok[j] = false; 80 printf("%d\n", p[i - 1].first + n - j); 81 return 0; 82 } 83 } 84 85 ok[p[i].second.first] = p[i].second.second; 86 int now = 0; 87 rep(j, 0, n) { 88 if (ok[j]) l[j] = now; 89 else now = j + 1; 90 } 91 now = n; 92 irep(j, n, 0) { 93 if (ok[j]) r[j] = now; 94 else now = j - 1; 95 } 96 97 rep(j, 0, n) { 98 if (!dp[i][j] || !ok[j]) continue;//即使j在这一轮可达,如果这时恰好来车了,其实也是不可达 99 dp[i + 1][max(l[j], j - p[i + 1].first + p[i].first)]++; 100 dp[i + 1][min(r[j], j + p[i + 1].first - p[i].first) + 1]--; 101 } 102 } 103 irep(j, n, 0) if (dp[2 * m][j]) { 104 printf("%d\n", p[2 * m].first + n - j); 105 break;//忘写break,WA一小时卧槽 106 } 107 return 0; 108 }
那么这就是全部的题目了~最强OJ,最强OJ.jpg(逃