zoukankan      html  css  js  c++  java
  • NOIP模拟测试13

    C题 60分扔扔扔,太遗憾了:(

    Problem A:矩阵游戏

    啥也不说了,先打了个40暴力。

    然后看到数据范围,想到肯定可以颓柿子。开始颓颓颓。

    一个点$(i, j)$的数字是$(i - 1)m + j$。最后的答案是$sum limits_{i=1}^n sum limits_{j=1}^m R_i S_j [(i-1)m + j]$.

    继续化简:

    原式 = $sum limits_{i=1}^n R_i sum limits_{j=1}^m S_j [(i-1)m + j]$ = $sum limits_{i=1}^n R_i  ((i-1) sum limits_{j=1}^m mS_j + sum limits_{j=1}^m jS_j)$

    $sum limits_{j=1}^m mS_j $ 和 $ sum limits_{j=1}^m jS_j$都可以$O(m)$线性求,最后再$O(n)$把答案求出来,得到一个$O(n + m)$的吼算法。

     1 #include <bits/stdc++.h>
     2 #define ll long long
     3 
     4 const int N = 1000000 + 233, MOD = 1000000007;
     5 ll n, m, k, R[N], S[N], sum_s1, sum_s2, ans;
     6 
     7 signed main() {
     8     scanf("%lld%lld%lld", &n, &m, &k);
     9     for (int i = 1; i <= n; i++) R[i] = 1ll;
    10     for (int i = 1; i <= m; i++) S[i] = 1ll;
    11     for (int i = 1; i <= k; i++) {
    12         char op[10]; ll x, y;
    13         scanf("%s%lld%lld", op, &x, &y);
    14         if (op[0] == 'R') {
    15             (R[x] *= y) %= MOD;
    16         } else {
    17             (S[x] *= y) %= MOD;
    18         }
    19     } 
    20     for (int i = 1; i <= m; i++) {
    21         sum_s1 = (sum_s1 + i * S[i]) % MOD;
    22         sum_s2 = (sum_s2 + m * S[i]) % MOD;
    23     }
    24     for (int i = 1; i <= n; i++) {
    25         ans = (ans + R[i] * ((sum_s1 + ((ll) i - 1ll) * sum_s2) % MOD) % MOD) % MOD;
    26     }
    27     return !printf("%lld
    ", ans);
    28 }
    A

     Problem B:跳房子

    考试的时候直接码了个一步一步挪的暴力。

    其实看出来有循环节了,但写起来细节太多,真心码不动Orz

    TKJ的这种方法很易于理解,而且很好码。

    我们只看每一列,每次移动等价于一次置换。

    开个线段树去维护置换,把区间+重载一下更方便。

    其他部分都按普通线段树写就行。

      1 #include <bits/stdc++.h>
      2 
      3 const int N = 2005;
      4 int n, m, q, val[N][N], x = 1, y = 1;
      5 
      6 class SegTree {
      7 private:
      8     struct Node {
      9         int nxt[N];
     10         friend Node operator *(Node a, Node b) {
     11             Node ret;
     12             for (int i = 1; i <= n; i++)
     13                 ret.nxt[i] = b.nxt[a.nxt[i]];
     14             return ret;
     15         }
     16     } t[N << 2];
     17     void build(int p, int l, int r) {
     18         if (l == r) {
     19             for (int i = 1; i <= n; i++) {
     20                 int yy = l == m ? 1 : l + 1;
     21                 int x_1 = i == n ? 1 : i + 1;
     22                 int x_2 = i == 1 ? n : i - 1;
     23                 int x_3 = i;
     24                 t[p].nxt[i] = val[x_1][yy] > val[x_2][yy] &&
     25                     val[x_1][yy] > val[x_3][yy] ? x_1 :
     26                     val[x_2][yy] > val[x_3][yy] ? x_2 : x_3;
     27             }
     28             return;
     29         }
     30         int mid = (l + r) >> 1;
     31         build(p << 1, l, mid), build(p << 1 | 1, mid + 1, r);
     32         t[p] = t[p << 1] * t[p << 1 | 1];
     33     }
     34     void _change(int p, int l, int r, int x) {
     35         if (l == r) {
     36             for (int i = 1; i <= n; i++) {
     37                 int yy = l == m ? 1 : l + 1;
     38                 int x_1 = i == n ? 1 : i + 1;
     39                 int x_2 = i == 1 ? n : i - 1;
     40                 int x_3 = i;
     41                 t[p].nxt[i] = val[x_1][yy] > val[x_2][yy] &&
     42                     val[x_1][yy] > val[x_3][yy] ? x_1 :
     43                     val[x_2][yy] > val[x_3][yy] ? x_2 : x_3;
     44             }
     45             return;
     46         } 
     47         int mid = (l + r) >> 1;
     48         if (x <= mid) _change(p << 1, l, mid, x);
     49         else _change(p << 1 | 1, mid + 1, r, x);
     50         t[p] = t[p << 1] * t[p << 1 | 1];
     51     }
     52     Node _query(int p, int l, int r, int L, int R) {
     53         if (l == L && r == R) return t[p];
     54         int mid = (L + R) >> 1;
     55         if (r <= mid) return _query(p << 1, l, r, L, mid);
     56         else if (l > mid) return _query(p << 1 | 1, l, r, mid + 1, R);
     57         else return _query(p << 1, l, mid, L, mid) * 
     58             _query(p << 1 | 1, mid + 1, r, mid + 1, R);
     59     }
     60     Node _qpow(Node x, int b) {
     61         Node ret;
     62         for (int i = 1; i <= n; i++) ret.nxt[i] = i;
     63         for (; b; b >>= 1, x = x * x)
     64             if (b & 1) ret = ret * x;
     65         return ret;
     66     }
     67 public:
     68     SegTree() {
     69         build(1, 1, m);
     70     }
     71     Node query(int l, int r) {
     72         return _query(1, l, r, 1, m);
     73     }
     74     void change(int x) {
     75         _change(1, 1, m, x);
     76     }
     77     Node qpow(int b) {
     78         return _qpow(t[1], b);
     79     }
     80 };
     81 
     82 signed main() {
     83     scanf("%d%d", &n, &m);
     84     for (int i = 1; i <= n; i++)
     85         for (int j = 1; j <= m; j++)
     86             scanf("%d", &val[i][j]);
     87     static SegTree *Gekoo = new SegTree();
     88     scanf("%d", &q);
     89     for (int i = 1; i <= q; i++) {
     90         char op[10]; int k, a, b, e;
     91         scanf("%s", op);
     92         if (op[0] == 'm') {
     93             scanf("%d", &k);
     94             if (!k) {
     95                 printf("%d %d
    ", x, y);
     96                 continue;
     97             }
     98             if (y + k - 1 <= m) {
     99                 x = Gekoo->query(y, y + k - 1).nxt[x];
    100                 y = (y + k - 1 == m) ? 1 : y + k;
    101             } else {
    102                 k -= m - y + 1;
    103                 x = Gekoo->query(y, m).nxt[x], y = 1;
    104                 if (k / m)
    105                     x = Gekoo->qpow(k / m).nxt[x];
    106                 if (k % m)
    107                     x = Gekoo->query(y, y + k % m - 1).nxt[x], 
    108                       y += k % m;
    109             }
    110             printf("%d %d
    ", x, y);
    111         } else {
    112             scanf("%d%d%d", &a, &b, &e);
    113             val[a][b] = e;
    114             Gekoo->change(b == 1 ? m : b - 1);
    115         }
    116     }
    117     return 0;
    118 }
    B

    Problem C:优美序列

    这题很像奇袭,一个区间是优美的,等价于$r - l = max_{[l, r]} - min_{[l, r]}$.

    可以用ST表暴力做:查询出询问区间的max和min,把它们作为端点继续查,直到不再改变,可以得84pt,不详谈,直接贴代码。

     1 #include <bits/stdc++.h>
     2 
     3 const int N = 100005;
     4 int n, m, pos[N], ori[N]; 
     5 int posmn[N][20], posmx[N][20], orimn[N][20], orimx[N][20], lg[N];
     6 
     7 inline int read() {
     8     int a = 0; char c = getchar();
     9     while (!isdigit(c)) c = getchar();
    10     while (isdigit(c)) a = a * 10 + c - '0', c = getchar();
    11     return a;
    12 }
    13 
    14 inline int query_orimx(int l, int r) {
    15     int t = lg[r - l + 1];
    16     return std::max(orimx[l][t], orimx[r-(1<<t)+1][t]);
    17 }
    18 
    19 inline int query_orimn(int l, int r) {
    20     int t = lg[r - l + 1];
    21     return std::min(orimn[l][t], orimn[r-(1<<t)+1][t]);
    22 }
    23 
    24 inline int query_posmx(int l, int r) {
    25     int t = lg[r - l + 1];
    26     return std::max(posmx[l][t], posmx[r-(1<<t)+1][t]);
    27 }
    28 
    29 inline int query_posmn(int l, int r) {
    30     int t = lg[r - l + 1];
    31     return std::min(posmn[l][t], posmn[r-(1<<t)+1][t]);
    32 }
    33 
    34 signed main() {
    35     n = read();
    36     for (int i = 1; i <= n; i++) {
    37         scanf("%d", ori + i);
    38         pos[ori[i]] = i;
    39     }
    40     for (int i =  1; i <= n; i++)
    41         posmx[i][0] = posmn[i][0] = pos[i],
    42         orimx[i][0] = orimn[i][0] = ori[i];
    43     for (register int j = 1; (1 << j) <= n; j++)
    44         for (register int i = 1; i <= n - (1 << j) + 1; i++)
    45             posmx[i][j] = std::max(posmx[i][j-1], posmx[i+(1<<(j-1))][j-1]),
    46             posmn[i][j] = std::min(posmn[i][j-1], posmn[i+(1<<(j-1))][j-1]),
    47             orimx[i][j] = std::max(orimx[i][j-1], orimx[i+(1<<(j-1))][j-1]),
    48             orimn[i][j] = std::min(orimn[i][j-1], orimn[i+(1<<(j-1))][j-1]);
    49     for (int i = 0, t = 0; i <= n; i++) {
    50         if (i >= (1 << (t + 1))) t++;
    51         lg[i] = t;
    52     }
    53     m = read();
    54     while (m--) {
    55         int l, r, pl = 0, pr = 0, omx, omn;
    56         l = read(), r = read();
    57         bool flg = 0;
    58         while (l != pl || r != pr) {
    59             if (flg) l = pl, r = pr;
    60             omx = query_orimx(l, r), omn = query_orimn(l, r);
    61             pl = query_posmn(omn, omx), pr = query_posmx(omn, omx);
    62             flg = 1;
    63         }
    64         printf("%d %d
    ", pl, pr);
    65     }
    66     return 0;
    67 }
    ST

    正解是分治,不提了,这里写的是DKY的线段树优化建图方法

    由上式,相邻两个数i, i + 1可以加入优美区间,仅当区间中出现了$[val_i, val_{i + 1}]$的所有值。

    用边连接节点,表示限制关系,用点向区间连边显然可以线段树优化。

    Tarjan缩点求SCC,DFS求出存在每个点所需要的区间。

    用线段树可以维护。原因不说了,显然。

    最后的答案就是区间内所有点对应区间的并。

      1 #include <bits/stdc++.h>
      2 
      3 const int INF = 0x3f3f3f3f, N = 400000 + 233;
      4 int pos[N], n, val[N], m;
      5 std::vector<int> G1[N], G2[N];
      6 bool vis[N];
      7 
      8 struct Node {
      9     int l, r;
     10     Node() {l = INF, r = -1;}
     11     Node(int ll, int rr) {l = ll, r = rr;}
     12     friend Node operator +(Node x, Node y) {
     13         return Node(std::min(x.l, y.l), std::max(x.r, y.r));    
     14     }
     15 };
     16 
     17 class SegTree {
     18 private:
     19     struct Tree {
     20         Node t[N];
     21         void _change(int p, int L, int R, int x, Node v) {
     22             if (L == R) return (void) (t[p] = v);
     23             int mid = (L + R) >> 1;
     24             if (x <= mid) _change(p << 1, L, mid, x, v);
     25             else _change(p << 1 | 1, mid + 1, R, x, v);
     26             t[p] = t[p<<1] + t[p<<1|1];
     27         }
     28         Node _query(int p, int L, int R, int l, int r) {
     29             if (l <= L && r >= R) return t[p];
     30             int mid = (L + R) >> 1;
     31             if (r <= mid) return _query(p << 1, L, mid, l, r);
     32             else if (l > mid) return _query(p << 1 | 1, mid + 1, R, l, r);
     33             else return _query(p << 1, L, mid, l, mid) +
     34                 _query(p << 1 | 1, mid + 1, R, mid + 1, r);
     35         }
     36     } seg[2];
     37     void _build(int p, int L, int R) {
     38         if (L == R) return (void) (pos[L] = p);
     39         int mid = (L + R) >> 1;
     40         _build(p << 1, L, mid), _build(p << 1 | 1, mid + 1, R);
     41         G1[p].push_back(p << 1), G1[p].push_back(p << 1 | 1);
     42     }
     43     void _addedge(int p, int L, int R, int l, int r, int q) {
     44         if (l <= L && r >= R) return (void) (G1[q].push_back(p));
     45         int mid = (L + R) >> 1;
     46         if (l <= mid) _addedge(p << 1, L, mid, l, r, q);
     47         if (r > mid) _addedge(p << 1 | 1, mid + 1, R, l, r, q);
     48     }
     49 public:
     50     SegTree() {
     51         _build(1, 1, n);
     52     }
     53     Node query(int id, int l, int r) {
     54         return seg[id]._query(1, 1, n, l, r);
     55     }
     56     void addedge(int l, int r, int q) {
     57         _addedge(1, 1, n, l, r, q);
     58     }
     59     void change(int id, int x, Node v) {
     60         seg[id]._change(1, 1, n, x, v);
     61     }
     62 };
     63 
     64 int dfn[N], low[N], stk[N], num, tp, scc[N], tot;
     65 bool ins[N];
     66  
     67 void Tarjan(int x) {
     68     dfn[x] = low[x] = ++num;
     69     ins[stk[++tp] = x] = 1;
     70     for (auto y : G1[x]) {
     71         if (!dfn[y]) {
     72             Tarjan(y);
     73             low[x] = std::min(low[x], low[y]);
     74         } else if (ins[y]) 
     75             low[x] = std::min(low[x], dfn[y]);
     76     }
     77     if (low[x] == dfn[x]) {
     78         int y; ++tot;
     79         do {
     80             ins[y = stk[tp--]] = 0, scc[y] = tot;
     81         } while (x != y);
     82     }
     83 }
     84 
     85 Node t1[N], t2[N];
     86 
     87 void dfs(int x) {
     88     if (vis[x]) return;
     89     vis[x] = 1;
     90     for (auto y : G2[x]) {
     91         dfs(y);
     92         t2[x] = t2[x] + t2[y]; 
     93     }
     94 }
     95 
     96 signed main() {
     97     scanf("%d", &n);
     98     for (int i = 1; i <= n; i++)
     99         scanf("%d", &val[i]);
    100     static SegTree *Gekoo = new SegTree();
    101     for (int i = 1; i <= n; i++)
    102         Gekoo->change(0, val[i], {i, i});
    103     for (int i = 2; i <= n; i++) {
    104         int l = std::min(val[i - 1], val[i]), r = std::max(val[i - 1], val[i]);
    105         t1[pos[i]] = Gekoo->query(0, l, r);
    106         Gekoo->addedge(t1[pos[i]].l + 1, t1[pos[i]].r, pos[i]);
    107     }
    108     for (int i = 1; i < N; i++)
    109         if (!dfn[i]) Tarjan(i);
    110     for (int x = 1; x < N; x++)
    111         for (auto y : G1[x])
    112             if (scc[x] != scc[y]) G2[scc[x]].push_back(scc[y]);
    113     for (int i = 1; i < N; i++)
    114         t2[scc[i]] = t2[scc[i]] + t1[i];
    115     for (int i = 1; i <= tot; i++) dfs(i);
    116     for (int i = 2; i <= n; i++)
    117         Gekoo->change(1, i, t2[scc[pos[i]]]);
    118     scanf("%d", &m);
    119     for (int i = 1, x, y; i <= m; i++) {
    120         scanf("%d%d", &x, &y);
    121         if (x == y) {
    122             printf("%d %d
    ", x, y);
    123         } else {
    124             Node ans = Gekoo->query(1, x + 1, y);
    125             printf("%d %d
    ", ans.l, ans.r);
    126         }
    127     }
    128     return 0;    
    129 }
    C
  • 相关阅读:
    进程与线程
    the art of seo(chapter seven)
    the art of seo(chapter six)
    the art of seo(chapter five)
    the art of seo(chapter four)
    the art of seo(chapter three)
    the art of seo(chapter two)
    the art of seo(chapter one)
    Sentinel Cluster流程分析
    Sentinel Core流程分析
  • 原文地址:https://www.cnblogs.com/gekoo/p/11306761.html
Copyright © 2011-2022 走看看