2018.10.05模拟总结

今天的题自认为比Day1简单一些,而且出的质量很高(虽然数据有点水)。

 

T1 a

  期望得分:30

  实际得分:30

  首先不得不吐槽一下:这题名字起的真糊弄。

  说下题吧,一拿到题发现O(n2)暴力就是送的,枚举起始点,再O(n)扫一遍。15分钟敲完后开始打表想想正解,发现对于一个数s[i],他对旋转k次的贡献有一部分是一个等差数列,而有一部分不是,准确说应该是分别有一个递增和递减,公差是1和-1的等差数列 ,以及单出来的一个1。于是我就想找规律,找了30多分钟硬是没找出来,不得不放弃写T2.

  T2,T3写完后又会来杠T1,总共用时1小时20分钟,还是只有暴力分……

  正解其实和我的思路比较像,但是他找到了等差数列的规律:s[i]对每一个答案的贡献可以分成三个等差数列,然后这道题就变成了区间加一个等差数列,最后求每一个数修改后的值。可以用线段树实现,不过更有的是二阶差分(详见这篇博客),总复杂度O(n)。

  但是规律比较复杂,没写出来。

  于是我们看第二种方法吧。

  强的过分的Dukelv用了不到40分钟AC了这道题,令人震惊。他跟我们说:就是暴力模拟啊!于是就有了一个O(n)暴力模拟的方法。

  对于每一次旋转,我们只用考虑旋转后相对于旋转前的答案变了什么,然后不断的维护当前的答案。

  因此我们需要一个big:记录当前有几个数s[i] >= i,以及sma:有几个数s[i] < i。然后每一次旋转,先考虑第一个数,因为他的移动方式和其他的都不一样:移到了最后,所以首先是big--, sma++,对答案的贡献少了s[i] - 1,多了n - s[i]。然后考虑剩下的数:有一些的答案由正变负,有一些有负变正。因此我们要开一个数组num[]记录当前有哪些数是负的(当然记录正的也行,反正一个就够了),num[x]表示 s[i] - i = -x的数有多少个,那也就是说,在第k次旋转后,num[k]的这些数就会有负变正,这样对于第 i 次旋转,big += num[i], sma -= num[i],于是对于big和sma的维护也完成了。

  有趣的是,标程的代码竟然和Dukelv一样,反而题解的做法没有代码。

先发个30分吧

 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 = 2e6 + 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 void MYFILE()
37 {
38 #ifndef mrclr
39     freopen("a.in", "r", stdin);
40     freopen("a.out", "w", stdout);
41 #endif    
42 }
43 
44 int n, a[maxn];
45 
46 ll ans = INF;
47 
48 int main()
49 {
50     MYFILE();
51     n = read();
52     for(rg int i = 1; i <= n; ++i) a[i] = read();
53     for(rg int i = 1; i <= n; ++i)
54     {
55         ll Min = 0;
56         for(rg int j = i, k = 1; k <= n; ++k, ++j)
57         {
58             if(j > n) j -= n;
59             Min += abs(a[j] - k);
60             if(Min > ans) break;
61         }
62         ans = min(ans, Min);
63     }
64     write(ans); enter;
65     return 0;
66 }
View Code

满分的

 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 = 2e6 + 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 void MYFILE()
37 {
38     
39 #ifndef mrclr
40     freopen("a.in", "r", stdin);
41     freopen("a.out", "w", stdout);
42 #endif    
43 }
44 
45 int n, a[maxn];
46 int big = 0, sma = 0, num[maxn << 1];
47 ll ans, Min = 0;
48 
49 int main()
50 {
51     MYFILE();
52     n = read();
53     for(int i = 1; i <= n; ++i)
54     {
55         a[i] = read();
56         int x = a[i] - i;
57         if(x >= 0) ++big, Min += x;
58         else ++sma, Min -= x, num[-x]++;
59     }
60     ans = Min;
61     for(int i = 1; i <= n; ++i)
62     {
63         int x = a[i] - 1, y = n - a[i];
64         big--; Min -= x;
65         sma++; Min += y; num[i + y]++;
66         Min += big - sma + 1;
67         if(num[i]) big += num[i], sma -= num[i];
68         ans = min(ans, Min);
69     }
70     write(ans); enter;
71     return 0;
72 }
View Code

(都好短)

 

T2 maze

  期望得分:30

  实际得分:10

  还是一眼秒30分,被卡掉20分是因为起点可能不合法,直接输出-1……出题人毒瘤的过分。

  正解我是无论如何也想不到的。看n特别小,觉得肯定要在这上面做文章,觉得可能是插头dp什么的,但最终还是没想出来。

  正解是咋回事儿呢:n这么小,那么我们就把他看成一个长度为m的序列吧!修改,查询用线段树维护就好啦~

  令人震惊。

  具体来说,就是对于一个区间[L, R],维护位于第L列所有的点到第R列所有的点的最短距离,也就是说,这个线段树上的每一个点是一个邻接矩阵,t[now].dis[i][j]表示a[i][L]到a[j][R]的最短距离!

  考虑修改:就是单点修改,然后暴力重构涉及到的每一个结点的矩阵。区间合并的时候,我们枚举左右子区间挨着的点,在枚举左子区间的起点和右子区间的终点,像floyd构造。

  查询:考虑起点和终点所在列不在同一区间的情况:其实和区间合并一样,floyd跑一遍,返回结构体。

  于是    写完了。感觉要是想到这个做法的话,这题就挺水的……

30分bfs暴力

 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 maxm = 2e5 + 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 void MYFILE()
37 {
38     freopen("maze.in", "r", stdin);
39 #ifndef mrclr
40     freopen("maze.out", "w", stdout);
41 #endif    
42 }
43 
44 int n, m, q;
45 bool a[6][maxm], vis[6][maxm];
46 int sx, sy, ex, ey;
47 const int dx[4] = {-1, 0, 1}, dy[4] = {0, 1, 0};
48 struct Node
49 {
50     int x, y, dis;
51 };
52 void bfs()
53 {
54     if(!a[sx][sy] || !a[ex][ey] || ey < sy) {write(-1), enter; return;}
55     for(int i = 1; i <= n; ++i)
56         for(int j = sy - 1; j <= ey + 1; ++j) vis[i][j] = 0;
57     queue<Node> q;
58     q.push((Node){sx, sy, 0});
59     vis[sx][sy] = 1;
60     while(!q.empty())
61     {
62         Node now = q.front(); q.pop();
63         if(now.x == ex && now.y == ey) {write(now.dis), enter; return;}
64         for(int i = 0; i < 3; ++i)
65         {
66             int newx = now.x + dx[i], newy = now.y + dy[i];
67             if(newx > 0 && newx <= n && newy > 0 && newy <= m && a[newx][newy] && !vis[newx][newy])
68             {
69                 vis[newx][newy] = 1;
70                 q.push((Node){newx, newy, now.dis + 1});
71             }
72         }
73     }
74     write(-1), enter;
75 }
76 
77 int main()
78 {
79     MYFILE();
80     n = read(); m = read(); q = read();
81     for(int i = 1; i <= n; ++i)
82         for(int j = 1; j <= m; ++j) a[i][j] = (bool)read();
83     for(int i = 1; i <= q; ++i)
84     {
85         int op = read();
86         if(op == 1) 
87         {
88             int x = read(), y = read();
89             a[x][y] ^= 1;
90         }
91         else
92         {
93             sx = read(), sy = read(), ex = read(), ey = read();
94             bfs();
95         }
96     }
97     return 0;
98 }
View Code

正解

  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 maxm = 2e5 + 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 void MYFILE()
 37 {
 38 #ifndef mrclr
 39     freopen("maze.in", "r", stdin);
 40     freopen("maze.out", "w", stdout);
 41 #endif    
 42 }
 43 
 44 int n, m, q, a[6][maxm];
 45 
 46 struct Tree
 47 {
 48     int l, r;
 49     int dis[6][6];
 50     Tree operator + (const Tree &oth)const
 51     {
 52         Tree ret;
 53         Mem(ret.dis, 0x3f);
 54         ret.l = l; ret.r = oth.r;
 55         for(int k = 1; k <= n; ++k) 
 56             for(int i = 1; i <= n; ++i)
 57                 for(int j = 1; j <= n; ++j)
 58                     ret.dis[i][j] = min(ret.dis[i][j], dis[i][k] + 1 + oth.dis[k][j]);
 59         return ret;
 60     }
 61 }t[maxm << 2];
 62 void build(int L, int R, int now)
 63 {
 64     t[now].l = L; t[now].r = R;
 65     if(L == R) 
 66     {
 67         Mem(t[now].dis, 0x3f);
 68         for(int i = 1; i <= n; ++i) 
 69             for(int j = i; j <= n; ++j) 
 70                 if(a[j][L]) t[now].dis[i][j] = t[now].dis[j][i] = j - i;
 71                 else break;
 72         return;
 73     }
 74     int mid = (L + R) >> 1;
 75     build(L, mid, now << 1);
 76     build(mid + 1, R, now << 1 | 1);
 77     t[now] = t[now << 1] + t[now << 1 | 1];
 78 }
 79 void update(int now, int d)
 80 {
 81     if(t[now].l == t[now].r) 
 82     {
 83         Mem(t[now].dis, 0x3f);
 84         for(int i = 1; i <= n; ++i) 
 85             for(int j = i; j <= n; ++j) 
 86                 if(a[j][t[now].l]) t[now].dis[i][j] = t[now].dis[j][i] = j - i;
 87                 else break;
 88         return;        
 89     }
 90     int mid = (t[now].l + t[now].r) >> 1;
 91     if(d <= mid) update(now << 1, d);
 92     else update(now << 1 | 1, d);
 93     t[now] = t[now << 1] + t[now << 1 | 1];
 94 }
 95 Tree query(int L, int R, int now)
 96 {
 97     if(L == t[now].l && R == t[now].r) return t[now];
 98     int mid = (t[now].l + t[now].r) >> 1;
 99     if(R <= mid) return query(L, R, now << 1);
100     else if(L > mid) return query(L, R, now << 1 | 1);
101     else return query(L, mid, now << 1) + query(mid + 1, R, now << 1 | 1);
102 }
103 
104 int main()
105 {
106     MYFILE();
107     n = read(); m = read(); q = read();
108     for(int i = 1; i <= n; ++i)
109         for(int j = 1; j <= m; ++j) a[i][j] = read();
110     build(1, m, 1);
111     for(int i = 1; i <= q; ++i)
112     {
113         int op = read();
114         if(op == 1)
115         {
116             int x = read(), y = read();
117             a[x][y] ^= 1; update(1, y);
118         }
119         else 
120         {
121             int sx = read(), sy = read(), ex = read(), ey = read();
122             int ans = query(sy, ey, 1).dis[sx][ex];
123             write(ans == INF ? -1 : ans); enter;
124         }
125     }
126     return 0;
127 }
View Code

 

 

T3 point

  期望得分:80~100

  实际得分:100

  这题我AC了!哈哈哈哈…………

  没错,我的方法就是正解。【得瑟】

  其实看到这题,我还是先想暴力:首先枚举区间长度len,然后枚举长度为len的所有区间,再对于每一个区间判断是否有价值:首先找区间最小值Min,然后找区间gcd,如果 Min | gcd (其实就是Min == gcd)的话就说明这个区间符合。加上求gcd的复杂度,O(n3logn)。

  然后我就想到,区间最小值和gcd可以用线段树实现,不用再O(nlogn)跑一遍,成功降到O(n2log2n)。

  然后想到st表预处理查询Min是O(1)的,gcd是O(logn)的,用st表吧,复杂度变成了O(n2logn)。

  最后想到枚举区间长度可以从大到小枚举,第一个符合的区间长度一定就是答案,但这样的话复杂度最坏还是能达到O(n2logn)。于是还是二分吧,稳定的O(logn)。于是最终的复杂度就是O(nlog2n)。

  总结一下:st表预处理区间最小值MIn和Gcd,复杂度O(nlog2n)。然后二分长度,O(nlogn)判断,复杂度还是O(nlog2n)。

判断的时候加上break,最后再统计区间个数,把优化做到极致。

  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 = 5e5 + 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 void MYFILE()
 37 {
 38 #ifndef mrclr
 39     freopen("point.in", "r", stdin);
 40     freopen("point.out", "w", stdout);
 41 #endif    
 42 }
 43 
 44 int n;
 45 
 46 inline int gcd(int x, int y)
 47 {
 48     return y ? gcd(y, x % y) : x;
 49 }
 50 int dp[maxn][21][2], ha[maxn];
 51 void rmq()
 52 {
 53     for(rg int i = 1; i <= n; ++i) dp[i][0][0] = dp[i][0][1] = read();
 54     for(rg int j = 1; (1 << j) <= n; ++j)
 55         for(rg int i = 1; i + (1 << j) - 1 <= n; ++i)
 56         {
 57             dp[i][j][0] = min(dp[i][j - 1][0], dp[i + (1 << (j - 1))][j - 1][0]);
 58             dp[i][j][1] = gcd(dp[i][j - 1][1], dp[i + (1 << (j - 1))][j - 1][1]);
 59         }
 60     int x = 0;
 61     for(rg int i = 1; i <= n; ++i)
 62     {
 63         ha[i] = x;
 64         if((1 << (x + 1)) <= i + 1) x++;
 65     }
 66 }
 67 inline int query_Min(const int &L, const int &R)    //卡常…… 
 68 {
 69     int k = ha[R - L + 1];
 70     return min(dp[L][k][0], dp[R - (1 << k) + 1][k][0]);
 71 }
 72 inline int query_Gcd(const int &L, const int &R)
 73 {
 74     int k = ha[R - L + 1];
 75     return gcd(dp[L][k][1], dp[R - (1 << k) + 1][k][1]);
 76 }
 77 
 78 bool judge(const int &len)
 79 {
 80     for(rg int i = 1; i + len - 1 <= n; ++i)
 81     {
 82         int L = i, R = i + len - 1;
 83         int Min = query_Min(L, R), Gcd = query_Gcd(L, R);
 84         if(!(Gcd % Min)) return true;
 85     }
 86     return false;
 87 }
 88 
 89 int num = 0;
 90 vector<int> ans;
 91 
 92 int main()
 93 {
 94     MYFILE();
 95     n = read();
 96     rmq();
 97     int L = 0, R = n;
 98     while(L < R)
 99     {
100         int mid = (L + R + 1) >> 1;
101         if(judge(mid)) L = mid;
102         else R = mid - 1;
103     }
104     for(rg int i = 1; i + L - 1 <= n; ++i)
105     {
106         int l = i, r = i + L - 1;
107         int Min = query_Min(l, r), Gcd = query_Gcd(l, r);
108         if(!(Gcd % Min)) num++, ans.push_back(i);
109     }
110     write(num); space; write(L - 1); enter;
111     for(rg int i = 0; i < (int)ans.size(); ++i) write(ans[i]), space;
112     enter;
113     return 0;
114 }
View Code

还特意写了个O(n3logn)对拍了一下,拍完4000组数据后安心了。

 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 = 5e5 + 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 void MYFILE()
37 {
38     freopen("random.in", "r", stdin);
39     freopen("bf.out", "w", stdout);
40 }
41 
42 int gcd(int x, int y)
43 {
44     return y ? gcd(y, x % y) : x;
45 }
46 
47 int n, a[maxn];
48 int num = 0, val;
49 vector<int> ans;
50 
51 int main()
52 {
53     MYFILE();
54     n = read();
55     for(int i = 1; i <= n; ++i) a[i] = read();
56     for(int len = n; len >= 0; --len)
57     {
58         bool flg = 0;
59         for(int i = 1; i + len - 1 <= n; ++i)
60         {
61             int L = i, R = i + len - 1;
62             int Min = INF;
63             for(int j = L; j <= R; ++j) Min = min(Min, a[j]);
64             int Gcd = Min;
65             for(int j = L; j <= R; ++j) Gcd = gcd(Gcd, a[j]);
66             if(!(Gcd % Min)) 
67             {
68                 if(!flg) {ans.clear(); num = 0; val = len;}
69                 flg = 1; num++;
70                 ans.push_back(L);
71             }
72         }
73         if(flg) break;
74     }
75     printf("%d %d\n", num, val - 1);
76     for(int i = 0; i < (int)ans.size(); ++i) write(ans[i]), space;
77     enter;
78     return 0;
79 }
View Code

 

其实这次模拟挺闲的,T3 40多分钟就敲完了,剩下的时间T1,T2也没抠出来,硬是坐了一个多点……

posted @ 2018-10-05 19:50  mrclr  阅读(336)  评论(4编辑  收藏  举报