CSP2020-S题解

A.儒略日

傻逼题,以后再说吧

B.动物园

傻逼题,以后也不会说

C.函数调用

考场冲的裸线段树可以获得 70pts 的好分数,数据 8 太行

solution:

容易发现这是一张 DAG

考虑只有全局乘的 case,发现可以通过一次记搜获得每个点的总共要乘的权值

然后把 f 数组调用的函数节点的权值乘起来 O(n) 更新原数组就行

那么有单点修改呢?可以发现如果一个点被加了 x,那他对答案的实际贡献是 $x \times mul$, mul 就是这个操作之后的所有乘法操作的积

一个位于 $f_i$ 子图里的一个加法操作的 mul 是多少呢?首先 $[f_j, f_n]$ 这个区间里的所有乘法操作的积是一定包含的,这已经在刚刚记搜中搞完了

现在就差 $f_i$ 子图里的乘法积了,怎么搞呢?容易发现,如果我们按照他 3 操作给的顺序从左到右建边的话,这个加法操作在这个子图中的积就是这个操作右侧的所有 mul 的乘积

所以我们可以通过 topo 排序获得答案,一个点向下枚举时顺序从右向左

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <cstdlib>
  6 #include <vector>
  7 #include <queue>
  8 #include <cctype>
  9 #define INF 0x7fffffff
 10 #define infP 100010
 11 
 12 namespace lrg {
 13 
 14 namespace io {
 15     const int SIZE = (1 << 21) + 1;
 16     char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
 17     
 18     #define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
 19     
 20     inline void flush () {
 21         fwrite (obuf, 1, oS - obuf, stdout);
 22         oS = obuf;
 23     }
 24     
 25     inline void putc (char x) {
 26         *oS ++ = x;
 27         if (oS == oT) flush ();
 28     }
 29     
 30     template <class I>
 31     inline void read (I &x) {
 32         for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;
 33         for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); 
 34         x *= f;
 35     }
 36     
 37     template <class I>
 38     inline void print (I x) {
 39         if (!x) putc ('0'); 
 40         if (x < 0) putc ('-'), x = -x;
 41         while (x) qu[++ qr] = x % 10 + '0',  x /= 10;
 42         while (qr) putc (qu[qr --]);
 43     }
 44     
 45     struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
 46 }
 47 using io :: read; using io :: putc; using io :: print;
 48 template <class T>
 49 inline void read(T &a, T &b) {read(a); read(b);}
 50 template <class T>
 51 inline void read(T &a, T &b, T &c) {read(a); read(b); read(c);}
 52 
 53 inline void setting() {
 54 #ifdef ONLINE_JUDGE
 55     freopen("call.in", "r", stdin);
 56     freopen("call.out", "w", stdout);
 57 #endif
 58 }
 59 
 60 const int ha = 998244353;
 61 
 62 int n, m, q;
 63 int a[infP], f[infP];
 64 int in[infP];
 65 int sum[infP], mul[infP];
 66 std::vector <int> opt[infP];
 67 std::queue <int> Q;
 68 
 69 inline int type(int x) {return opt[x][0];}
 70 
 71 int dfsMul(int x) {
 72     static bool vis[infP];
 73     if(vis[x]) return mul[x]; vis[x] = 1;
 74     if(type(x) == 1) return mul[x] = 1;
 75     if(type(x) == 2) return mul[x] = opt[x][1];
 76     mul[x] = 1;
 77     for(auto i = opt[x].begin() + 1; i != opt[x].end(); i++) 
 78         mul[x] = 1ll * mul[x] * dfsMul(*i) % ha;
 79     return mul[x];
 80 }
 81 
 82 inline void topoSum() {
 83     for(int i = 1; i <= m; i++) {
 84         if(in[i] == 0) Q.push(i);
 85     }
 86     while(!Q.empty()) {
 87         int x = Q.front(); Q.pop();
 88         int now = 1;
 89         if(type(x) != 3) continue;
 90         for(auto i = opt[x].end() - 1; i != opt[x].begin(); i--) {
 91             int y = *i;
 92             sum[y] = (sum[y] + 1ll * now * sum[x] % ha) % ha;
 93             now = 1ll * now * mul[y] % ha;
 94             if(--in[y] == 0) Q.push(y);
 95         }
 96     }
 97 }
 98 
 99 inline void main () {
100     setting();
101     read(n);
102     for(int i = 1; i <= n; i++) read(a[i]);
103     read(m);
104     for(int i = 1; i <= m; i++) {
105         int t; read(t); opt[i].push_back(t);
106         if(t == 1) {
107             int p, v; read(p, v);
108             opt[i].push_back(p);
109             opt[i].push_back(v);
110         } else if(t == 2) {
111             int v; read(v);
112             opt[i].push_back(v);
113         } else {
114             int c, f; read(c);
115             for(int j = 1; j <= c; j++) read(f), opt[i].push_back(f), ++in[f];
116         }
117     }
118     read(q);
119     for(int i = 1; i <= q; i++) read(f[i]);
120     std::reverse(f + 1, f + 1 + q);
121     for(int i = 1; i <= m; i++) {
122         if(in[i] == 0) dfsMul(i);
123     }
124     for(int i = 1, now = 1; i <= q; i++) {
125         sum[f[i]] = (sum[f[i]] + now) % ha;
126         now = (1ll * now * mul[f[i]] % ha);
127     }
128     topoSum();
129     int tot = 1;
130     for(int i = 1; i <= q; i++) tot = 1ll * tot * mul[f[i]] % ha;
131     for(int i = 1; i <= n; i++) a[i] = 1ll * a[i] * tot % ha;
132     for(int i = 1; i <= m; i++) {
133         if(type(i) != 1) continue;
134         a[opt[i][1]] = (a[opt[i][1]] + 1ll * opt[i][2] * sum[i] % ha) % ha;
135     }
136     for(int i = 1; i <= n; i++) print(a[i]), putc(' ');
137     putc('\n');
138     return;
139 }
140 
141 }
142 
143 signed main () {
144     lrg::main () ;
145     return 0;
146 }

D.贪吃蛇

容易发现一个性质

一般情况下,n 号蛇吃掉 1 号蛇后下一秒,如果他不在最头上也不在最末尾,那么 n-1 号蛇吃掉 2 号蛇之后一定在他前面,因为 $a_{n}-a_1 > a_{n-1}-a_2$

有了这条性质再来看本题

如果一个蛇吃了蛇,那么他只有两种case:1.他不在最头上;2.他在最头上

首先思考 case1:如果他不在最头上,那么来考虑一下 n-1 号蛇,又因为上面的性质,所以如果这两条蛇后面会被吃,那一定是 n-1 号蛇先被吃,所以这整个问题都递归到了 n-1 号蛇 case

也就是说,如果 case1,那么这条蛇一定会选择吃,这很好,问题只剩 case2 了

子 case1:如果 n-1 号蛇选择吃了之后问题成为 case1,那么蛇 n-1 一定会吃掉蛇 n,那么 n 一定会选择不吃,讨论结束

子 case2:如果 n-1 号蛇吃了之后变成了 case2,那么递归至子 case1

容易发现,这个 game 一定会在 n 和 n-1 中的一方上停止,也容易发现,停止在谁身上和 case2 的递归次数的奇偶性有关

所以,做完了

 

 

???真的做完了嘛?

显然我们的蛇权值数组需要是有序的,那么一条蛇开餐后,这个新蛇应该塞到哪里呢?

我们需要维护一个数组,支持$O(1)$删除头节点,查询任意位置,任意位置插入

这好像做不了吧?

所以我们考虑一个这个题一开始的性质,就是后面吃的蛇的剩余权值一定比前面的小,所以可以发现,吃完后的权值也是具有单调性的

所以,我们不妨维护两个双端队列,第一个是初始蛇,第二个是塞的都是剩余权值

我们要维护他的单调递增性质,所以任意时刻,如果这个时刻的蛇要选择进餐,那一定是这两个队列的尾较大的吃掉两个队列的头的较小的

因为我们还要维护单调性,所以剩余权值直接塞进 deque2 的头,正确性见上面性质

所以,这才真正做完了

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <cstdlib>
  6 #include <vector>
  7 #include <queue>
  8 #include <cctype>
  9 #include <deque>
 10 #define ll long long
 11 #define INF 0x7fffffff
 12 #define inf 1000010
 13 
 14 namespace lrg {
 15 
 16 namespace io {
 17     const int SIZE = (1 << 21) + 1;
 18     char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
 19     
 20     #define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
 21     
 22     inline void flush () {
 23         fwrite (obuf, 1, oS - obuf, stdout); 
 24         oS = obuf;
 25     }
 26     
 27     inline void putc (char x) {
 28         *oS ++ = x;
 29         if (oS == oT) flush ();
 30     }
 31     
 32     template <class I>
 33     inline void read (I &x) {
 34         for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;
 35         for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); 
 36         x *= f;
 37     }
 38     
 39     template <class I>
 40     inline void print (I x) {
 41         if (!x) putc ('0'); 
 42         if (x < 0) putc ('-'), x = -x;
 43         while (x) qu[++ qr] = x % 10 + '0',  x /= 10;
 44         while (qr) putc (qu[qr --]);
 45     }
 46     
 47     struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
 48 }
 49 using io :: read; using io :: putc; using io :: print;
 50 template <class T>
 51 inline void read(T &a, T &b) {read(a); read(b);}
 52 template <class T>
 53 inline void read(T &a, T &b, T &c) {read(a); read(b); read(c);}
 54 
 55 inline void setting() {
 56     freopen("snakes.in", "r", stdin);
 57     freopen("snakes.out", "w", stdout);
 58 }
 59 
 60 #define pii std::pair <int, int>
 61 
 62 int n, ans;
 63 int a[inf];
 64 
 65 std::deque <pii> Q;
 66 std::deque <pii> E;
 67 
 68 inline void clear() {
 69     Q.clear();
 70     E.clear();
 71     ans = 1;
 72 }
 73 
 74 inline void solve() {
 75     static int test1 = 1;
 76     if(test1) {
 77         read(n);
 78         for(int i = 1; i <= n; i++) read(a[i]);
 79         test1 = 0;
 80     } else {
 81         clear();
 82         int k; read(k);
 83         for(int i = 1; i <= k; i++) {
 84             int x, y; read(x, y); 
 85             a[x] = y;
 86         }
 87     }
 88     for(int i = 1; i <= n; i++) Q.push_back(std::make_pair(a[i], i));
 89     int now = 0;
 90     while(Q.size() + E.size() > 2) {
 91         int eaten = 0;
 92         if(E.empty() || Q.front() < E.front()) eaten = Q.front().first, Q.pop_front();
 93         else eaten = E.front().first, E.pop_front();
 94         pii act;
 95         if(E.empty() || Q.back() > E.back()) act = Q.back(), Q.pop_back();
 96         else act = E.back(), E.pop_back();
 97         pii minus = std::make_pair(act.first - eaten, act.second);
 98         pii comp = std::min(Q.front(), E.empty() ? Q.front() : E.front());
 99         if(minus < comp) {
100             if(now == 0) ans = Q.size() + E.size() + 1;
101             ++now;
102         } else if(now) break;
103         E.push_front(minus);
104     }
105     ans += (now & 1);
106     printf("%d\n", ans);
107     return;
108 }
109 
110 inline void main () {
111     setting();
112     int T; read(T);
113     while(T--) solve();
114     return;
115 }
116 
117 }
118 
119 signed main () {
120     lrg::main () ;
121     return 0;
122

 

这场比赛题都挺有意思的(除了A),给个好评(除了A),但是自己这场得分好像全靠 rp 啊/wul

具体游记见我 luogu blog

NOIP2020 ++rp, ++score;!!!

posted @ 2020-11-29 14:54  Chiaro  阅读(197)  评论(0)    收藏  举报