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
  • 相关阅读:
    Filter的基本配置
    11.3、4(filter的生命周期和API)、
    11.1(过滤器概述)、(创建过滤器filter)
    10.6商品的促销活动,(未解决)
    php 调用常量或者变量的时候千万不能加引号""'' 不然不生效
    thinkphp5 if else的表达式怎么写?
    request() 获取参数是数组不是对象
    thinkphp5 PATHINFO路由正确的访问方式
    thinkphp5 的iframe文件怎么显示到html里面
    thinkphp5引入外部css js文件
  • 原文地址:https://www.cnblogs.com/gekoo/p/11306761.html
Copyright © 2011-2022 走看看