做题&学习记录(2月)

2020.2.3

学了一点多项式理论,感觉似懂非懂。。

[SCOI2015]小凸玩密室

首先注意到这是一颗完全二叉树,因为高度很小所以可以枚举每个点作为起点。

然后考虑树形DP,求出每个点往上爬的代价即可。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long ll;
 5 const int MAXN = 200010;
 6 #define p(i, j) (((1 << (j - 1)) <= i) ? (i >> j) : -1)
 7 #define b(i, j) ((i >> (j - 1)) ^ 1)
 8 #define ls (i << 1)
 9 #define rs (i << 1 | 1)
10 
11 int n; ll num[MAXN];
12 ll dis[MAXN][20], dp[MAXN][20][2];
13 
14 int main()
15 {
16     scanf("%d", &n);
17     for(int i = 1; i <= n; ++i) scanf("%lld", &num[i]);
18     for(int i = 2; i <= n; ++i)
19     {
20         scanf("%lld", &dis[i][1]);
21         for(int j = 2; ~p(i, j); ++j) dis[i][j] = dis[i][1] + dis[p(i, 1)][j - 1];
22     }
23     for(int i = n; i; --i)
24         for(int j = 1; ~p(i, j); ++j)
25         {
26             dp[i][j][0] = dp[i][j][1] = 0x3f3f3f3f3f3f3f3f;
27             int lson = ls, rson = rs;
28             if((i << 1) > n)
29             {
30                 dp[i][j][0] = dis[i][j] * num[p(i, j)];
31                 dp[i][j][1] = (dis[i][j] + dis[b(i, j)][1]) * num[b(i, j)];
32             }
33             else if((i << 1 | 1) > n)
34             {
35                 dp[i][j][0] = dis[ls][1] * num[ls] + dp[ls][j + 1][0];
36                 dp[i][j][1] = dis[ls][1] * num[ls] + dp[ls][j + 1][1];
37             }
38             else
39             {
40                 dp[i][j][0] = min(dp[i][j][0], dis[ls][1] * num[ls] + dp[ls][1][1] + dp[rs][j + 1][0]);
41                 dp[i][j][0] = min(dp[i][j][0], dis[rs][1] * num[rs] + dp[rs][1][1] + dp[ls][j + 1][0]);
42                 dp[i][j][1] = min(dp[i][j][1], dis[ls][1] * num[ls] + dp[ls][1][1] + dp[rs][j + 1][1]);
43                 dp[i][j][1] = min(dp[i][j][1], dis[rs][1] * num[rs] + dp[rs][1][1] + dp[ls][j + 1][1]);
44             }
45         }
46     ll ans = 0x3f3f3f3f3f3f3f3f;
47     for(int s = 1; s <= n; ++s)
48     {
49         ll tmp = dp[s][1][0];
50         for(int i = p(s, 1), lst = s; ~i; i = p(i, 1), lst = p(lst, 1))
51         {
52             if(b(lst, 1) <= n) tmp += dis[b(lst, 1)][1] * num[b(lst, 1)] + dp[b(lst, 1)][2][0];
53             else tmp += dis[i][1] * num[p(i, 1)];
54         }
55         ans = min(ans, tmp);
56     }
57     printf("%lld\n", ans);
58     return 0;
59 }

2020.2.4

[SCOI2015]小凸玩矩阵 

二分,然后最大流判定即可。

 [YNOI2019]排队

[YNOI2019]数字游戏

[YNOI2019]逆序对

做了一下隔壁省的省选题,,这也太水了。。

 [SHOI2015]脑洞治疗仪

线段树维护一个最大连续子段,修改的话可以在线段树上一层层递归下去,直到当前区间能全部一次改成1再修改,时间复杂度是$O(nlog^2n)$的。

数据结构题有点难写,放个代码吧。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 
  4 const int MAXN = 200010;
  5 #define ls (o << 1)
  6 #define rs (o << 1 | 1)
  7 
  8 struct Node
  9 {
 10     int l, r, lazy;
 11     int sum, Sum;
 12 }t[MAXN << 2];
 13 
 14 int n, m, tot, cnt;
 15 
 16 Node pushup(int l, int r, Node a, Node b, int tag)
 17 {
 18     Node o = (Node){a.l, b.r, tag, a.r + b.l, a.Sum + b.Sum};
 19     int mid = (l + r) >> 1;
 20     if(a.l == mid - l + 1) o.l += b.l;
 21     if(b.r == r - mid) o.r += a.r;
 22     o.sum = max(o.sum, max(a.sum, b.sum));
 23     o.sum = max(o.sum, max(o.l, o.r));
 24     return o;
 25 }
 26 
 27 void pushdown(int o, int l, int r)
 28 {
 29     int tag = t[o].lazy;
 30     t[o].lazy = -1;
 31     if(tag == -1) return;
 32     int mid = (l + r) >> 1;
 33     t[ls].Sum = tag * (mid - l + 1);
 34     t[ls].sum = t[ls].l = t[ls].r = (tag == 0) * (mid - l + 1);
 35     t[ls].lazy = tag;
 36     t[rs].Sum = tag * (r - mid);
 37     t[rs].sum = t[rs].l = t[rs].r = (tag == 0) * (r - mid);
 38     t[rs].lazy = tag;
 39 }
 40 
 41 void change0(int o, int l, int r, int L, int R)
 42 {
 43     if(l == L && r == R)
 44     {
 45         t[o].Sum = 0;
 46         t[o].sum = t[o].l = t[o].r = r - l + 1;
 47         t[o].lazy = 0;
 48         return;
 49     }
 50     pushdown(o, l, r);
 51     int mid = (l + r) >> 1;
 52     if(R <= mid) change0(ls, l, mid, L, R);
 53     else if(L > mid) change0(rs, mid + 1, r, L, R);
 54     else change0(ls, l, mid, L, mid), change0(rs, mid + 1, r, mid + 1, R);
 55     t[o] = pushup(l, r, t[ls], t[rs], t[o].lazy);
 56 }
 57 
 58 void change1(int o, int l, int r)
 59 {
 60     if(!cnt) return;
 61     if(t[o].Sum == r - l + 1) return;
 62     if(!t[o].Sum && cnt >= r - l + 1)
 63     {
 64         t[o].Sum = r - l + 1;
 65         t[o].sum = t[o].l = t[o].r = 0;
 66         t[o].lazy = 1;
 67         cnt -= r - l + 1, tot += r - l + 1;
 68         return;
 69     }
 70     if(l >= r) return;
 71     pushdown(o, l, r);
 72     int mid = (l + r) >> 1;
 73     change1(ls, l, mid); change1(rs, mid + 1, r);
 74     t[o] = pushup(l, r, t[ls], t[rs], t[o].lazy);
 75 }
 76 
 77 void modify(int o, int l, int r, int L, int R, int tag)
 78 {
 79     if(tot >= tag) return;
 80     if(l == L && r == R)
 81     {
 82         cnt = tag - tot;
 83         change1(o, l, r);
 84         return;
 85     }
 86     pushdown(o, l, r);
 87     int mid = (l + r) >> 1;
 88     if(R <= mid) modify(ls, l, mid, L, R, tag);
 89     else if(L > mid) modify(rs, mid + 1, r, L, R, tag);
 90     else modify(ls, l, mid, L, mid, tag), modify(rs, mid + 1, r, mid + 1, R, tag);
 91     t[o] = pushup(l, r, t[ls], t[rs], t[o].lazy);
 92 }
 93 
 94 int ask1(int o, int l, int r, int L, int R)
 95 {
 96     if(l == L && r == R) return t[o].Sum;
 97     pushdown(o, l, r);
 98     int mid = (l + r) >> 1;
 99     if(R <= mid) return ask1(ls, l, mid, L, R);
100     else if(L > mid) return ask1(rs, mid + 1, r, L, R);
101     else return ask1(ls, l, mid, L, mid) + ask1(rs, mid + 1, r, mid + 1, R);
102 }
103 
104 Node ask2(int o, int l, int r, int L, int R)
105 {
106     if(l == L && r == R) return t[o];
107     pushdown(o, l, r);
108     int mid = (l + r) >> 1;
109     if(R <= mid) return ask2(ls, l, mid, L, R);
110     else if(L > mid) return ask2(rs, mid + 1, r, L, R);
111     Node a = ask2(ls, l, mid, L, mid), b = ask2(rs, mid + 1, r, mid + 1, R);
112     return pushup(l, r, a, b, -1);
113 }
114 
115 int main()
116 {
117     scanf("%d %d", &n, &m);
118     t[1].lazy = 1, t[1].Sum = n;
119     for(int i = 1; i <= m; ++i)
120     {
121         int op, l, r, l1, r1;
122         scanf("%d %d %d", &op, &l, &r);
123         if(!op) change0(1, 1, n, l, r);
124         else if(op == 1)
125         {
126             scanf("%d %d", &l1, &r1);
127             int tag = ask1(1, 1, n, l, r);
128             change0(1, 1, n, l, r);
129             if(tag) tot = cnt = 0, modify(1, 1, n, l1, r1, tag);
130         }
131         else if(op == 2) printf("%d\n", ask2(1, 1, n, l, r).sum);
132     }
133     return 0;
134 }

 


2020.2.5

[FJOI2015]火星商店问题

线段树套可持久化Trie,每个节点用Vector存一下时间,查询的时候二分即可。

顺便复习了一下可持久化结构。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 
  4 const int MAXN = 100010;
  5 #define ls (o << 1)
  6 #define rs (o << 1 | 1)
  7 
  8 int n, m, rt[MAXN];
  9 
 10 struct Trie
 11 {
 12     int ch[2], sum;
 13 }t[MAXN * 120];
 14 int cnt = 0;
 15 
 16 void ins(int& o, int p, int d, int val)
 17 {
 18     o = ++cnt, t[o] = t[p];
 19     ++t[o].sum;
 20     if(d == -1) return;
 21     bool c = (val & (1 << d));
 22     ins(t[o].ch[c], t[p].ch[c], d - 1, val);
 23 }
 24 
 25 int ask(int l, int r, int d, int val)
 26 {
 27     if(d == -1 || (!l && !r)) return 0;
 28     bool c = (val & (1 << d));
 29     if(t[t[r].ch[!c]].sum - t[t[l].ch[!c]].sum > 0) return (1 << d) + ask(t[l].ch[!c], t[r].ch[!c], d - 1, val);
 30     else return ask(t[l].ch[c], t[r].ch[c], d - 1, val);
 31 }
 32 
 33 struct Node
 34 {
 35     vector<int> times, ids;
 36     int nowrt;
 37 }s[MAXN << 2];
 38 
 39 void build(int o, int l, int r)
 40 {
 41     s[o].times.push_back(0);
 42     s[o].ids.push_back(0);
 43     s[o].nowrt = 0;
 44     if(l == r) return;
 45     int mid = (l + r) >> 1;
 46     build(ls, l, mid);
 47     build(rs, mid + 1, r);
 48 }
 49 
 50 void modify(int o, int l, int r, int pos, int val, int day)
 51 {
 52     s[o].times.push_back(day);
 53     int copy = 0;
 54     ins(copy, s[o].nowrt, 17, val);
 55     s[o].ids.push_back(copy);
 56     s[o].nowrt = copy;
 57     if(l == r) return;
 58     int mid = (l + r) >> 1;
 59     if(pos <= mid) modify(ls, l, mid, pos, val, day);
 60     else modify(rs, mid + 1, r, pos, val, day);
 61 }
 62 
 63 int query(int o, int l, int r, int L, int R, int x, int d, int day)
 64 {
 65     if(L <= l && r <= R)
 66     {
 67         if(s[o].times.size() <= 1 || s[o].times.back() < day - d + 1) return 0;
 68         int siz = (int)s[o].times.size();
 69         int l = 1, r = siz - 1, ans = siz - 1;
 70         while(l <= r)
 71         {
 72             int mid = (l + r) >> 1;
 73             if(s[o].times[mid] >= day - d + 1) ans = mid, r = mid - 1;
 74             else l = mid + 1;
 75         }
 76         return ask(s[o].ids[ans - 1], s[o].nowrt, 17, x);
 77     }
 78     int mid = (l + r) >> 1, res = 0;
 79     if(L <= mid) res = max(res, query(ls, l, mid, L, R, x, d, day));
 80     if(R > mid) res = max(res, query(rs, mid + 1, r, L, R, x, d, day));
 81     return res;
 82 }
 83 
 84 int main()
 85 {
 86     int day = 0;
 87     scanf("%d %d", &n, &m);
 88     for(int i = 1; i <= n; ++i)
 89     {
 90         int x; scanf("%d", &x);
 91         ins(rt[i], rt[i - 1], 17, x);
 92     }
 93     build(1, 1, n);
 94     while(m--)
 95     {
 96         int op, l, r, x, d;
 97         scanf("%d", &op);
 98         if(!op) ++day;
 99         if(!op)
100         {
101             scanf("%d %d", &x, &d);
102             modify(1, 1, n, x, d, day);
103         }
104         else if(op == 1)
105         {
106             scanf("%d %d %d %d", &l, &r, &x, &d);
107             int ans = ask(rt[l - 1], rt[r], 17, x);
108             ans = max(ans, query(1, 1, n, l, r, x, d, day));
109             printf("%d\n", ans);
110         }
111     }
112     return 0;
113 }

 


2020.2.6

[SHOI2015]聚变反应炉

二合一的题目,$c_i<=1$时贪心,否则做一个类似背包的树形DP即可。

[BJOI2015]树的同构

做法很多,什么最小表示法等等,不过直接简单粗暴的树哈希就可以了。

posted @ 2020-02-03 20:16  Aegir  阅读(100)  评论(0编辑  收藏  举报