Atcoder 杂题 round 1
目录:
abc190D
abc190E
abc190F
abc192D
abc192E
abc192F
abc201D
abc201E
abc190D
可以发现存在负数的答案都是由一个不存在负数的答案推过来的,比如 [-2,-1,...,4,5] 就是由 [3,4,5] 推过来的,所以这一部分答案不用考虑
可以想到答案的区间个数和因子有关,又可以发现区间长度应当是个奇数
所以答案应当是他的奇素数个数
(abc190 题解鸽太久了有点记不清思路了(
abc190E
容易想到可以连边建图,两个 gem 间需要填塞的宝石数就是两点距离,然后可以发现 k 很小,又因为不用考虑顺序,所以可以直接状压dp解决
abc190F
可以发现一次转换等于是在这个序列的末尾删一个元素,队首加一个元素,可以用树状数组维护逆序对来做这题
1 #include <ctime> 2 #include <cmath> 3 #include <cctype> 4 #include <cstdio> 5 #include <cstring> 6 #include <cstdlib> 7 #include <iostream> 8 #include <algorithm> 9 #include <vector> 10 #include <queue> 11 #define inf 300010 12 #define INF 0x7fffffff 13 #define ll long long 14 15 template <class I> 16 inline void read(I &num){ 17 num = 0; char c = getchar(), up = c; 18 while(!isdigit(c)) up = c, c = getchar(); 19 while(isdigit(c)) num = (num << 1) + (num << 3) + (c ^ '0'), c = getchar(); 20 up == '-' ? num = -num : 0; return; 21 } 22 template <class I> 23 inline void read(I &a, I &b) {read(a); read(b);} 24 template <class I> 25 inline void read(I &a, I &b, I &c) {read(a); read(b); read(c);} 26 27 int n; 28 int a[inf]; 29 30 struct bitTree { 31 private: 32 int c[inf]; 33 inline int lowbit(const int &x) {return x & (-x);} 34 35 public: 36 inline void insert(int x, int k) { 37 ++x; 38 while(x <= n) { 39 c[x] += k; 40 x += lowbit(x); 41 } 42 } 43 44 inline int query(int x) { 45 ++x; int res = 0; 46 while(x) { 47 res += c[x]; 48 x -= lowbit(x); 49 } 50 return res; 51 } 52 }; 53 54 bitTree bt; 55 ll nx[inf], ans[inf]; 56 57 signed main(){ 58 read(n); 59 for(int i = 1; i <= n; i++) read(a[i]); 60 for(int i = n; i; i--) { 61 nx[i] = bt.query(a[i]); 62 bt.insert(a[i], 1); 63 } 64 for(int i = 1; i <= n; i++) ans[0] += nx[i]; 65 for(int i = 1; i < n; i++) { 66 ans[i] = ans[i - 1] - a[i] + (n - 1 - a[i]); 67 } 68 for(int i = 0; i < n; i++) printf("%lld\n", ans[i]); 69 return 0; 70 }
abc192D
并没有打算写这题题解,只是来骂一下,垃圾题
abc192E
可以发现对于任意一个节点,我们都应该尽可能快地到达它,这样答案绝对是最优的
所以我们等于在这张图上求最短路,简单魔改一下 dijkstra 即可
#include <ctime> #include <cmath> #include <cctype> #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #include <vector> #include <queue> #define inf 200010 #define INF 0x7ffffffffffffffll #define ll long long template <class I> inline void read(I &num){ num = 0; char c = getchar(), up = c; while(!isdigit(c)) up = c, c = getchar(); while(isdigit(c)) num = (num << 1) + (num << 3) + (c ^ '0'), c = getchar(); up == '-' ? num = -num : 0; return; } template <class I> inline void read(I &a, I &b) {read(a); read(b);} template <class I> inline void read(I &a, I &b, I &c) {read(a); read(b); read(c);} struct edge { int to; ll t, k; edge *next; }; edge *g[inf]; inline void connect(int from, int to, ll t, ll k) { static edge pool[inf]; static edge *p = pool; p->to = to; p->t = t; p->k = k; p->next = g[from]; g[from] = p++; return; } ll dis[inf]; int n, m, s, t; struct Node { ll dis; int pos; Node () {} Node (ll a, int b) { this->dis = a, this->pos = b; } inline bool operator < (const Node &t) const { return dis > t.dis; } }; inline void dij(int s) { static std::priority_queue <Node> P; static bool vis[inf]; std::fill(dis, dis + 1 + n, INF >> 1); P.push(Node(0, s)); dis[s] = 0; while(!P.empty()) { int x = P.top().pos; P.pop(); if(vis[x]) continue; vis[x] = 1; for(auto e = g[x]; e; e = e->next) { int y = e->to; ll dist; if(dis[x] % e->k == 0) dist = dis[x] + e->t; else dist = (dis[x] / e->k + 1) * e->k + e->t; if(dis[y] > dist) { dis[y] = dist; if(vis[y] == 0) P.push(Node(dis[y], y)); } } } return; } signed main(){ read(n, m); read(s, t); for(int i = 1; i <= m; i++) { int x, y, t, k; read(x, y); read(t, k); connect(x, y, t, k); connect(y, x, t, k); } dij(s); printf("%lld\n", dis[t] == (INF >> 1) ? -1 : dis[t]); return 0; }
abc192F
考虑枚举个数,对于一个固定的个数 p,我们要做的就是最大化在模 p 意义下 p 个元素的和,使之等于 x。可以通过 dp 来解决
设 dpi,j,k 表示前 i 个元素里选了 j 个元素,j 个元素之和在模 p 意义等于 k
O(n4),跑不满
abc201D
容易发现(i+j)为奇数的地方一定是 A 拿走,(i+j) 为偶数的地方一定是 B 拿走。维护两个变量比较困难,发现可以转化为:A 的目标是最大化 (scoreA−scoreB), B 的目标是最小化 (scoreA−scoreB)
我们考虑倒叙 dp,可以发现
如果 (i+j) 为奇数 f(i,j)=max
如果 (i+j) 为偶数 f(i,j)=\min[f(i+1,j)-w(i+1,j),f(i,j+1)-w(i,j+1)]
比赛的时候怎么没想到 dp 啊啊啊啊啊啊啊啊啊
abc201E
可以发现 dis(i,j)=dis(x,i)\oplus dis(x,j)
设 1 为根,可以先获得 dis(1,k),那么我们现在要做的就是 O(\log n) 时间内获得 \sum_{i\leq n}(dis(1,i)\oplus(1,k))
即对一个固定数列a求其所有元素对一个定值k异或后的和,我们先记 a 的和为 s
考虑我的“脑筋急转弯”里面的一道小题,我们把数列a全转换成二进制,然后搞一个桶b,b_i记录有多少个元素二进制第 i 位是1
然后把 k 也转成二进制,当 k 第 i 位是 1 的时候,那么 a 的所有元素这一位都会翻转,即原来这一位是 1 的全变成 0,0 的全变成 1,那么翻转后这一位会增加/减少的量可以通过 b_i 计算出来,把 s 加/减 增加/减少 的量 \times 2^i 即对答案的贡献
还有一个小问题,dis(k,1) 会这么被算成 0,所以我们需要额外加上一个 \sum_{i\leq n}dis(1,k),即上文中的 s 。最后答案别忘了除以二
复杂度 O(\log n),总复杂度 O(n\log n)
1 #include <ctime> 2 #include <cmath> 3 #include <cctype> 4 #include <cstdio> 5 #include <cstring> 6 #include <cstdlib> 7 #include <iostream> 8 #include <algorithm> 9 #include <vector> 10 #include <queue> 11 #define inf 200010 12 #define INF 0x7fffffff 13 #define int long long 14 15 template <class I> 16 inline void read(I &num){ 17 num = 0; char c = getchar(), up = c; 18 while(!isdigit(c)) up = c, c = getchar(); 19 while(isdigit(c)) num = (num << 1) + (num << 3) + (c ^ '0'), c = getchar(); 20 up == '-' ? num = -num : 0; return; 21 } 22 template <class I> 23 inline void read(I &a, I &b) {read(a); read(b);} 24 template <class I> 25 inline void read(I &a, I &b, I &c) {read(a); read(b); read(c);} 26 27 const int ha = 1e9 + 7; 28 29 struct edge { 30 int to; 31 int val; 32 edge *nxt; 33 }; 34 35 int n; 36 edge *g[inf]; 37 int dis[inf]; 38 int pos[100]; 39 40 inline void connect(int from, int to, int val) { 41 static edge pool[inf << 1]; 42 static auto p = pool; 43 p->to = to; 44 p->val = val; 45 p->nxt = g[from]; 46 g[from] = p++; 47 } 48 49 void DFS(int x, int f) { 50 for(auto e = g[x]; e; e = e->nxt) { 51 if(e->to == f) continue; 52 dis[e->to] = (dis[x] ^ e->val); 53 DFS(e->to, x); 54 } 55 } 56 57 inline int ksm(int a, int b, int ha){ 58 int ans = 1; 59 while(b){ 60 if(b & 1) ans = ans * a % ha; 61 a = a * a % ha; 62 b >>= 1; 63 } 64 return ans; 65 } 66 67 signed main(){ 68 read(n); 69 for(int i = 1; i < n; i++) { 70 int u, v, w; read(u, v, w); 71 connect(u, v, w); 72 connect(v, u, w); 73 } 74 DFS(1, 0); 75 int sum = 0; 76 for(int i = 1; i <= n; i++) sum = (sum + dis[i]) % ha; 77 for(int i = 1; i <= n; i++) { 78 int t = dis[i]; 79 for(int j = 0; j <= 60; j++) { 80 pos[j] += (t & 1); 81 t >>= 1; 82 } 83 } 84 int ans = sum; 85 for(int i = 2; i <= n; i++) { 86 ans = (ans + sum) % ha; 87 int t = dis[i]; 88 for(int j = 0; j <= 60; j++) { 89 if(t & 1) { 90 ans = (ans + ((n - 1 - 2 * pos[j]) % ha) * ((1ll << j) % ha) % ha) % ha; 91 } 92 t >>= 1; 93 } 94 } 95 std::cout << ((ans + sum) % ha * ksm(2, ha - 2, ha) % ha + ha) % ha << '\n'; 96 return 0; 97 }
【推荐】2025 HarmonyOS 鸿蒙创新赛正式启动,百万大奖等你挑战
【推荐】博客园的心动:当一群程序员决定开源共建一个真诚相亲平台
【推荐】开源 Linux 服务器运维管理面板 1Panel V2 版本正式发布
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 别做抢活的导演:代码中的抽象层次原则
· 从 Redis 客户端超时到 .NET 线程池挑战
· C23和C++26的#embed嵌入资源指南
· 「EF Core」框架是如何识别实体类的属性和主键的
· 独立开发,这条路可行吗?
· 从 Redis 客户端超时到 .NET 线程池挑战:饥饿、窃取与阻塞的全景解析
· 2025年中总结:我想我克服公众演讲的恐惧了,一个社恐分子突破自我的故事
· 阿里巴巴为什么禁止超过3张表join?
· 实践经验:互联网项目起步指南
· 让 AI 帮我部署网站,太方便了!