AB水题就不说了
C .算概率
其实也是水题,n^2的概率dp,但是我场上没看这道题(雾
简单的状态转移方程dp[n][m]记录前n道题做出m道的概率
dp[n][m] = dp[n - 1][m - 1] * p[n] + dp[n - 1][m] * (1 - p[n]);
//dp[n][m] = dp[n - 1][m - 1] * p[n] + dp[n - 1][m] * (1 - p[n]); #include <cstdio> using namespace std; typedef long long ll; const int N = 2020; const ll MOD = 1e9 + 7; ll p[N], dp[N][N]; int main() { int n; scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%lld", &p[i]); dp[0][0] = 1; for (int i = 1; i <= n; i++) { dp[i][0] = dp[i - 1][0] * (1 - p[i] + MOD) % MOD; for (int j = 1; j <= i; j++) dp[i][j] = (dp[i - 1][j - 1] * p[i] % MOD + dp[i - 1][j] * (1 - p[i] + MOD) % MOD) % MOD; } for (int i = 0; i <= n; i++) printf("%lld ", dp[n][i]); return 0; }
D.数三角
不难,但是我被坑了很久,刚开始是没有判断共线,直角各种各样的东西,后来还被EPS卡了,总之非常绝望。
#include <cstdio> #include <cmath> using namespace std; const int N = 510; int pos[N][2]; const long double EPS = 1e-10; struct vector { long long x, y; }; inline long long dis(int a, int b) { long long u = (pos[a][0] - pos[b][0]) * (pos[a][0] - pos[b][0]) + (pos[a][1] - pos[b][1]) * (pos[a][1] - pos[b][1]); return u; } int main() { int n; scanf("%d", &n); for (int i = 0; i < n; i++) scanf("%d %d", &pos[i][0], &pos[i][1]); int tot = 0; for (int i = 0; i < n; i++) for (int j = i + 1; j < n; j++) for (int k = j + 1; k < n; k++) { long long ik = dis(i, k), jk = dis(j, k), ij = dis(i, j); if (sqrt(ik) + sqrt(jk) - sqrt(ij) < EPS || sqrt(ik) + sqrt(ij) - sqrt(jk) < EPS || sqrt(jk) + sqrt(ij) - sqrt(ik) < EPS) // 判断是否共线 continue; vector a = {pos[k][0] - pos[i][0], pos[k][1] - pos[i][1]}; //用点积判断 vector b = {pos[k][0] - pos[j][0], pos[k][1] - pos[j][1]}; long double res = 1ll * a.x * b.x + 1ll * a.y * b.y; if (res < 0) { tot++; continue; } if (res < EPS) //等于直角就没必要再考虑了,节省时间 continue; a.x = pos[i][0] - pos[k][0]; a.y = pos[i][1] - pos[k][1]; b.x = pos[i][0] - pos[j][0]; b.y = pos[i][1] - pos[j][1]; res = 1ll * a.x * b.x + 1ll * a.y * b.y; if (res < 0) { tot++; continue; } if (res < EPS) continue; a.x = pos[j][0] - pos[k][0]; a.y = pos[j][1] - pos[k][1]; b.x = pos[j][0] - pos[i][0]; b.y = pos[j][1] - pos[i][1]; res = 1ll * a.x * b.x + 1ll * a.y * b.y; if (res < 0) { tot++; continue; } } printf("%d", tot); return 0; }
F.拿物品
同类型贪心的明明见过很多次了,但是再次碰到我又崩了qwq,每次这种题都是排序乱搞就出来了,这个也不例外。
你可以想一想,你拿了一个,相当于你多了一个,对方少了一个,所以两者加起来排序就可以了
#include <cstdio> #include <algorithm> using namespace std; const int N = 2 * 1e5 + 10; typedef pair <int, int> P; P a[N]; #define f first #define s second int main() { int n; scanf("%d", &n); for (int i = 0; i < n; i++) scanf("%d", &a[i].f), a[i].s = i + 1; for (int i = 0; i < n; i++) { int k; scanf("%d", &k); a[i].f += k; } sort(a, a + n); for (int i = n - 1; i >= 0; i -= 2) printf("%d ", a[i].s); puts(""); for (int i = n - 2; i >= 0; i -= 2) printf("%d ", a[i].s); return 0; }
H.施魔法
dp,dp的状态转移方程倒是挺好想的,但是我一开始就没有把这道题联系到DP上去,不过需要用前缀最小值优化一下
#include <cstdio> #include <algorithm> using namespace std; const int N = 3 * 1e5 + 10; int a[N], d[N], pre[N]; int main() { int n, k; scanf("%d %d", &n, &k); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); sort(a + 1, a + n + 1); for (int i = 1; i < k; i++) pre[i] = -a[1]; d[k] = a[k] - a[1]; pre[k] = d[k] - a[k + 1]; for (int i = k + 1; i <= n; i++) { d[i] = pre[i - k] + a[i]; pre[i] = min(pre[i - 1], d[i] - a[i + 1]); } printf("%d", d[n]); return 0; } // d[i] = min{d[i - k] - a[i - k + 1]} + a[i];
I.建通道
思维题,理解lowbit和xor的性质就能很好做。
就是要注意一个问题,离散化的时候第一个单独处理,否则如果第一个是0容易误判
#include <cstdio> #include <algorithm> using namespace std; const int N = 2 * 1e5 + 10; int v[N]; int a[N]; int cnt = 0; int main() { int n; scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &v[i]); sort(v + 1, v + n + 1); a[++cnt] = v[1]; for (int i = 2; i <= n; i++) if (v[i] != v[i - 1]) a[++cnt] = v[i]; int k = -1; for (int i = 0; i <= 31; i++) { bool flag1 = false, flag2 = false; for (int j = 1; j <= cnt; j++) { if ((1 << i) & a[j]) flag1 = true; else flag2 = true; if (flag1 && flag2) break; } if (flag1 && flag2) { k = i; break; } } long long ans = 1ll * (1 << k) * (cnt - 1); printf("%lld", ans); return 0; }
J. 求函数
线段树,就是合并的过程比较有趣
#include <cstdio> #include <algorithm> using namespace std; #define g(l, r) (l + r | l != r) #define o g(l, r) #define ls g(l, mid) #define rs g(mid + 1, r) typedef long long ll; const ll MOD = 1e9 + 7; const int N = 2 * 1e5 + 10; ll k[N], b[N], sum1[N << 1], sum2[N << 1]; int L, R; void build(int l, int r) { if (l == r) { sum1[o] = k[l] % MOD; sum2[o] = b[l] % MOD; return ; } int mid = l + r >> 1; build(l, mid); build(mid + 1, r); sum1[o] = sum1[ls] * sum1[rs] % MOD; sum2[o] = (sum2[ls] * sum1[rs] % MOD + sum2[rs]) % MOD; } void update(int l, int r, int p, ll kp, ll bp) { if (l == r) { sum1[o] = kp % MOD; sum2[o] = bp % MOD; return ; } int mid = l + r >> 1; if (p <= mid) update(l, mid, p, kp, bp); else update(mid + 1, r, p, kp, bp); sum1[o] = sum1[ls] * sum1[rs] % MOD; sum2[o] = (sum2[ls] * sum1[rs] % MOD + sum2[rs]) % MOD; } ll query1(int l, int r) { if (l >= L && r <= R) { return sum1[o]; } int mid = l + r >> 1; ll ans = -1; if (mid >= L) ans = query1(l, mid); if (mid < R) { if (ans == -1) ans = query1(mid + 1, r); else ans = query1(mid + 1, r) * ans % MOD; } return ans % MOD; } ll query2(int l, int r) { if (l >= L && r <= R) return sum2[o]; int mid = l + r >> 1; ll ans = -1; if (mid >= L) ans = query2(l, mid); if (mid < R) { if (ans == -1) ans = query2(mid + 1, r); else ans = (ans * query1(mid + 1, r) % MOD + query2(mid + 1, r)) % MOD; } return ans % MOD; } int main() { int n, m; scanf("%d %d", &n, &m); for (int i = 1; i <= n; i++) scanf("%lld", &k[i]); for (int i = 1; i <= n; i++) scanf("%lld", &b[i]); build(1, n); while (m--) { int flag; scanf("%d", &flag); if (flag == 1) { int i; ll k, b; scanf("%d %lld %lld", &i, &k, &b); update(1, n, i, k, b); } else { scanf("%d %d", &L, &R); ll ans = (query1(1, n) + query2(1, n)) % MOD; printf("%lld ", ans); } } return 0; }