Loading [MathJax]/jax/element/mml/optable/BasicLatin.js

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 的目标是最大化 (scoreAscoreB), B 的目标是最小化 (scoreAscoreB)

我们考虑倒叙 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 }
复制代码

 

posted @   Chiaro  阅读(116)  评论(0)    收藏  举报
编辑推荐:
· 别做抢活的导演:代码中的抽象层次原则
· 从 Redis 客户端超时到 .NET 线程池挑战
· C23和C++26的#embed嵌入资源指南
· 「EF Core」框架是如何识别实体类的属性和主键的
· 独立开发,这条路可行吗?
阅读排行:
· 从 Redis 客户端超时到 .NET 线程池挑战:饥饿、窃取与阻塞的全景解析
· 2025年中总结:我想我克服公众演讲的恐惧了,一个社恐分子突破自我的故事
· 阿里巴巴为什么禁止超过3张表join?
· 实践经验:互联网项目起步指南
· 让 AI 帮我部署网站,太方便了!
点击右上角即可分享
微信分享提示