• 2018.10.03模拟总结


    在十一国庆期间,我们给祖国过生日,祖国妈妈可高兴了,让gg特意为我们准备了一场模拟!

     

    其实这一次的模拟不算太毒瘤,部分分还是可以拿到的,不过考完调正解的时候调到崩溃……

     

    T1 matrix

      这道题起手就是30。

      然后我憋了一会儿:这题有一个特别的地方,就是所有询问都在修改之后,那也就应当把所有修改做完,然后快速的询问。

      于是想到了一个类似扫描线的做法,把修改排序,然后维护一棵线段树,区间修改,单点查询,复杂度是O(nqlogn),只能60,结果考试的时候我还算成了O(qlogn),以为能AC……

      正解其实比扫描线简单多了:二维差分!这就是为什么n, m <= 2000了:一是能O(n2),二是能开的下二维数组。于是对于一个矩形的修改(xa, ya)到(xb, yb),我们模仿一维差分,dif[xa][ya]++; dif[xa][yb + 1]--; dif[xb + 1][ya]--; dif[xb + 1][yb + 1]++ 即可(dif是差分数组)。

      最后跑一遍二维前缀和,得到了修改后的矩阵,于是询问的时候就是O(1)的二维前缀和了。

    60分代码(线段树区间修改可以改成差分,达到O(nq),然鹅还是60)

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cmath>
      4 #include<algorithm>
      5 #include<cstring>
      6 #include<cstdlib>
      7 #include<cctype>
      8 #include<vector>
      9 #include<stack>
     10 #include<queue>
     11 using namespace std;
     12 #define enter puts("") 
     13 #define space putchar(' ')
     14 #define Mem(a, x) memset(a, x, sizeof(a))
     15 #define rg register
     16 typedef long long ll;
     17 typedef double db;
     18 const int INF = 0x3f3f3f3f;
     19 const db eps = 1e-8;
     20 const int maxn = 2e3 + 5;
     21 inline ll read()
     22 {
     23     ll ans = 0;
     24     char ch = getchar(), last = ' ';
     25     while(!isdigit(ch)) {last = ch; ch = getchar();}
     26     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
     27     if(last == '-') ans = -ans;
     28     return ans;
     29 }
     30 inline void write(ll x)
     31 {
     32     if(x < 0) x = -x, putchar('-');
     33     if(x >= 10) write(x / 10);
     34     putchar(x % 10 + '0');
     35 }
     36 
     37 int n, m, p, q;
     38 
     39 int a[maxn][maxn];
     40 ll Sum[maxn][maxn];
     41 
     42 int l[maxn << 2], r[maxn << 2], lzy[maxn << 2], sum[maxn << 2];
     43 void build(const int& L, const int& R, const int& now)
     44 {
     45     l[now] = L; r[now] = R;
     46     if(L == R) return;
     47     int mid = (L + R) >> 1;
     48     build(L, mid, now << 1);
     49     build(mid + 1, R, now << 1 | 1);
     50 }
     51 void pushdown(const int& now)
     52 {
     53     if(lzy[now])
     54     {
     55         sum[now << 1] += (r[now << 1] - l[now << 1] + 1) * lzy[now];
     56         sum[now << 1 | 1] += (r[now << 1 | 1] - l[now << 1 | 1] + 1) * lzy[now];
     57         lzy[now << 1] += lzy[now];
     58         lzy[now << 1 | 1] += lzy[now];
     59         lzy[now] = 0;
     60     }
     61 }
     62 void update(const int& L, const int& R, const int& now, const int& flg)
     63 {
     64     if(L == l[now] && R == r[now])
     65     {
     66         sum[now] += (R - L + 1) * flg;
     67         lzy[now] += flg; return;
     68     }
     69     pushdown(now);
     70     int mid = (l[now] + r[now]) >> 1;
     71     if(R <= mid) update(L, R, now << 1, flg);
     72     else if(L > mid) update(L, R, now << 1 | 1, flg);
     73     else update(L, mid, now << 1, flg), update(mid + 1, R, now << 1 | 1, flg);
     74     sum[now] = sum[now << 1] + sum[now << 1 | 1];
     75 }
     76 int query(const int& idx, const int& now)
     77 {
     78     if(sum[now] == 0) return 0;
     79     if(l[now] == r[now]) return sum[now];
     80     pushdown(now);
     81     int mid = (l[now] + r[now]) >> 1;
     82     if(idx <= mid) return query(idx, now << 1);
     83     else return query(idx, now << 1 | 1);
     84 }
     85 
     86 struct Node1
     87 {
     88     int L, R, flg;
     89 };
     90 vector<Node1> v1[maxn];
     91 
     92 int main()
     93 {
     94     freopen("matrix.in", "r", stdin);
     95     freopen("matrix.out", "w", stdout);
     96     n = read(); m = read(); p = read(); q = read();
     97     build(1, n, 1);
     98     for(rg int i = 1; i <= p; ++i)
     99     {
    100         int xa = read(), ya = read(), xb = read(), yb = read();
    101         v1[ya].push_back((Node1){xa, xb, 1}); v1[yb + 1].push_back((Node1){xa, xb, -1});
    102     }
    103     for(rg int i = 1; i <= m; ++i)
    104     {
    105         for(rg int j = 0; j < (int)v1[i].size(); ++j)
    106             update(v1[i][j].L, v1[i][j].R, 1, v1[i][j].flg);
    107         for(rg int j = 1; j <= n; ++j) a[j][i] = query(j, 1);
    108     }
    109     for(rg int i = 1; i <= n; ++i)
    110         for(rg int j = 1; j <= m; ++j) 
    111             Sum[i][j] = Sum[i][j - 1] + Sum[i - 1][j] - Sum[i - 1][j - 1] + a[i][j];
    112     for(rg int i = 1; i <= q; ++i)
    113     {
    114         int xa = read(), ya = read(), xb = read(), yb = read();
    115         write(Sum[xb][yb] - Sum[xb][ya - 1] - Sum[xa - 1][yb] + Sum[xa - 1][ya - 1]);
    116         enter;    
    117     }
    118     return 0;
    119 }
    View Code

    100分代码

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cctype>
     8 #include<vector>
     9 #include<stack>
    10 #include<queue>
    11 using namespace std;
    12 #define enter puts("") 
    13 #define space putchar(' ')
    14 #define Mem(a, x) memset(a, x, sizeof(a))
    15 #define rg register
    16 typedef long long ll;
    17 typedef double db;
    18 const int INF = 0x3f3f3f3f;
    19 const db eps = 1e-8;
    20 const int maxn = 2e3 + 5;
    21 inline ll read()
    22 {
    23     ll ans = 0;
    24     char ch = getchar(), last = ' ';
    25     while(!isdigit(ch)) {last = ch; ch = getchar();}
    26     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
    27     if(last == '-') ans = -ans;
    28     return ans;
    29 }
    30 inline void write(ll x)
    31 {
    32     if(x < 0) x = -x, putchar('-');
    33     if(x >= 10) write(x / 10);
    34     putchar(x % 10 + '0');
    35 }
    36 
    37 int n, m, p, q;
    38 
    39 int a[maxn][maxn], dif[maxn][maxn];
    40 ll sum[maxn][maxn];
    41 
    42 int main()
    43 {
    44     freopen("matrix.in", "r", stdin);
    45     freopen("matrix.out", "w", stdout);
    46     n = read(); m = read(); p = read(); q = read();
    47     for(rg int i = 1; i <= p; ++i)
    48     {
    49         int xa = read(), ya = read(), xb = read(), yb = read();
    50         dif[xa][ya]++; dif[xa][yb + 1]--; dif[xb + 1][ya]--; dif[xb + 1][yb + 1]++;
    51     }
    52     
    53     for(rg int i = 1; i <= n; ++i)
    54         for(rg int j = 1; j <= m; ++j) 
    55             a[i][j] = a[i][j - 1] + a[i - 1][j] - a[i - 1][j - 1] + dif[i][j];
    56     for(rg int i = 1; i <= n; ++i)
    57         for(rg int j = 1; j <= m; ++j) 
    58             sum[i][j] = sum[i][j - 1] + sum[i - 1][j] - sum[i - 1][j - 1] + a[i][j];    
    59     for(rg int i = 1; i <= q; ++i)
    60     {
    61         int xa = read(), ya = read(), xb = read(), yb = read();
    62         write(sum[xb][yb] - sum[xb][ya - 1] - sum[xa - 1][yb] + sum[xa - 1][ya - 1]);
    63         enter;    
    64     }
    65     return 0;
    66 }
    View Code

    T2 card

       O(n3):送的,令dp[i][j]表示第 i 个人选编号为 j 时的方案数,则dp[i][j] = sum(dp[i - 1][h]) (h : 1 ~ m, h + j != k)。然后答案就是sum(dp[n][i]) (i : 1 ~ m)。

      O(n2):维护一个sum[m],表示sum(dp[i]) (i : 1 ~ m),然后就可以省去 h 的一层循环。

      O(n) : 发现,sum[i][m]只跟sum[i - 1][m] 和sum[i - 1][k  - 1]有关,线性dp即可。

      O(logn):矩阵快速幂。然而不会把二维的状态降成一维的,gg。

    模拟的时候,推错了O(n)做法,忽视了k > m的情况,得了50.

    放一个考场代码吧

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cctype>
     8 #include<vector>
     9 #include<stack>
    10 #include<queue>
    11 using namespace std;
    12 #define enter puts("") 
    13 #define space putchar(' ')
    14 #define Mem(a, x) memset(a, x, sizeof(a))
    15 #define rg register
    16 typedef long long ll;
    17 typedef double db;
    18 const int INF = 0x3f3f3f3f;
    19 const db eps = 1e-8;
    20 const ll mod = 1e9 + 7;
    21 inline ll read()
    22 {
    23     ll ans = 0;
    24     char ch = getchar(), last = ' ';
    25     while(!isdigit(ch)) {last = ch; ch = getchar();}
    26     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
    27     if(last == '-') ans = -ans;
    28     return ans;
    29 }
    30 inline void write(ll x)
    31 {
    32     if(x < 0) x = -x, putchar('-');
    33     if(x >= 10) write(x / 10);
    34     putchar(x % 10 + '0');
    35 }
    36 
    37 int m, n, k;
    38 
    39 ll sum, sumk_1;
    40 
    41 int main()
    42 {
    43     freopen("card.in", "r", stdin);
    44     freopen("card.out", "w", stdout);
    45     m = read(); n = read(); k = read();
    46     sum = m; sumk_1 = k - 1;
    47     for(rg int i = 2; i <= n; ++i)
    48     {
    49         ll tp = sum;
    50         sum = (m * tp % mod - sumk_1 + mod) % mod;
    51         sumk_1 = ((k - 1) * tp % mod - sumk_1 + mod) % mod;
    52     }
    53     write(sum); enter;
    54     return 0;
    55 }
    View Code

    T3 station

      最暴力的做法是O(n3),然而什么分都得不到。

      对于上述O(n3),枚举车站的时候其实不用再O(n)求一遍,可以用前缀和维护,达到O(n2)。

      在枚举车站的时候,能得到一个很重要的规律,就是当车站向右移动,车站左侧的人的距离增大,右侧的减少,对答案的贡献的变化量就是车站左边人数 - 右边人数。看出总距离是先减少后增大的,因此找最值即可。

      于是80分就有了:用线段树或树状数组维护前缀和,每一次询问相当于单点修改,然后二分查找一个最小的x使得sum(x) >= 1 / 2 * sum(n),复杂度O(qlog2n)。

      100分就是直接有线段树维护,然后再线段树上查询极值点:判断左子区间的sum是否大于等于当前的值,是的话就到左子区间找,否则到右子区间找,直到L == R,返回L即可。

      然后我线段树就gg了,怎么也该不对。

      于是按题解的树状数组倍增写了一发。

    模拟时20分的

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cctype>
     8 #include<vector>
     9 #include<stack>
    10 #include<queue>
    11 using namespace std;
    12 #define enter puts("") 
    13 #define space putchar(' ')
    14 #define Mem(a, x) memset(a, x, sizeof(a))
    15 #define rg register
    16 typedef long long ll;
    17 typedef double db;
    18 const int INF = 0x3f3f3f3f;
    19 const db eps = 1e-8;
    20 const int maxn = 2e5 + 5;
    21 const ll mod = 998244353;
    22 const ll CONST = 19260817;
    23 inline ll read()
    24 {
    25     ll ans = 0;
    26     char ch = getchar(), last = ' ';
    27     while(!isdigit(ch)) {last = ch; ch = getchar();}
    28     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
    29     if(last == '-') ans = -ans;
    30     return ans;
    31 }
    32 inline void write(ll x)
    33 {
    34     if(x < 0) x = -x, putchar('-');
    35     if(x >= 10) write(x / 10);
    36     putchar(x % 10 + '0');
    37 }
    38 
    39 int n, q;
    40 ll a[maxn], sum[maxn], s_mul[maxn];
    41 
    42 int solve()
    43 {
    44     ll Min = (ll)INF * (ll)INF;
    45     int pos;
    46     for(rg int i = 1; i <= n; ++i)
    47     {
    48         ll tp = ((sum[i] * i) << 1) - (s_mul[i] << 1) + s_mul[n] - sum[n] * i;
    49         if(tp < Min) Min = tp, pos = i;
    50     }
    51     return pos;
    52 }
    53 
    54 ll ans = 0, bas = 1;
    55 
    56 int main()
    57 {
    58     freopen("station.in", "r", stdin);
    59     freopen("station.out", "w", stdout);
    60     n = read(); q = read();
    61     for(rg int i = 1; i <= n; ++i) a[i] = read();
    62     for(rg int i = 1; i <= q; ++i)
    63     {
    64         int x = read(); ll b = read();
    65         a[x] += b;
    66         for(rg int j = 1; j <= n; ++j) sum[j] = sum[j - 1] + a[j], s_mul[j] = s_mul[j - 1] + a[j] * j;
    67         (bas *= CONST) %= mod;
    68         (ans += bas * solve()) %= mod; 
    69     }
    70     write(ans); enter;    
    71     return 0;
    72 }
    View Code

    100分的

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cctype>
     8 #include<vector>
     9 #include<stack>
    10 #include<queue>
    11 using namespace std;
    12 #define enter puts("") 
    13 #define space putchar(' ')
    14 #define Mem(a, x) memset(a, x, sizeof(a))
    15 #define rg register
    16 typedef long long ll;
    17 typedef double db;
    18 const int INF = 0x3f3f3f3f;
    19 const db eps = 1e-8;
    20 const ll mod = 998244353;
    21 const ll CONST = 19260817;
    22 const int maxn = (1 << 20) + 5;
    23 inline ll read()
    24 {
    25     ll ans = 0;
    26     char ch = getchar(), last = ' ';
    27     while(!isdigit(ch)) {last = ch; ch = getchar();}
    28     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
    29     if(last == '-') ans = -ans;
    30     return ans;
    31 }
    32 inline void write(ll x)
    33 {
    34     if(x < 0) x = -x, putchar('-');
    35     if(x >= 10) write(x / 10);
    36     putchar(x % 10 + '0');
    37 }
    38 
    39 int n, p;
    40 
    41 ll c[maxn], sum = 0;
    42 int lowbit(int x)
    43 {
    44     return x & -x;
    45 }
    46 void add(int pos, ll d)
    47 {
    48     for(; pos < maxn; pos += lowbit(pos)) c[pos] += d; 
    49     sum += d;
    50 }
    51 int query(ll x)
    52 {
    53     int pos = 0; ll res = 0;
    54     for(int i = (1 << 17); i; i >>= 1) if(res + c[pos + i] <= x) pos += i, res += c[pos];
    55     return pos + 1;
    56 }
    57 
    58 ll ans = 0, bas = 1;
    59 
    60 int main()
    61 {
    62     freopen("station.in", "r", stdin);
    63     freopen("station.out", "w", stdout);
    64     n = read(); p = read();
    65     for(int i = 1; i <= n; ++i) {ll x = read(); add(i, x);}
    66     for(int i = 1; i <= p; ++i) 
    67     {
    68         int x = read(); ll d = read();
    69         add(x, d); 
    70         bas = bas * CONST % mod;
    71         ans = (ans + bas * query((sum - 1) >> 1)) % mod;
    72     }
    73     write(ans); enter;
    74     return 0;
    75 }
    View Code
  • 相关阅读:
    矩阵游戏|ZJOI2007|BZOJ1059|codevs1433|luoguP1129|二分图匹配|匈牙利算法|Elena
    BZOJ3262: 陌上花开
    BZOJ1176: [Balkan2007]Mokia
    BZOJ1261: [SCOI2006]zh_tree
    BZOJ2004: [Hnoi2010]Bus 公交线路
    BZOJ1066: [SCOI2007]蜥蜴
    BZOJ1294: [SCOI2009]围豆豆Bean
    BZOJ2756: [SCOI2012]奇怪的游戏
    BZOJ1857: [Scoi2010]传送带
    BZOJ1237: [SCOI2008]配对
  • 原文地址:https://www.cnblogs.com/mrclr/p/9740256.html
Copyright © 2020-2023  润新知