1. 程式人生 > >【十一模擬】總結

【十一模擬】總結

復雜 ati pda 部分 否則 splay algorithm double using

在十一國慶期間,我們給祖國過生日,祖國媽媽可高興了,讓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

【十一模擬】總結