十一模拟总结
Posted mrclr
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了十一模拟总结相关的知识,希望对你有一定的参考价值。
在十一国庆期间,我们给祖国过生日,祖国妈妈可高兴了,让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 }
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 }
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 }
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 }
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 }
以上是关于十一模拟总结的主要内容,如果未能解决你的问题,请参考以下文章