NOIP模拟测试14

以前的坑,填一下。

写在前面的:以后我的考试感想将主要写自己的反思,题解之类的就略写了,主要能让我自己回忆起来就行。

想看详细题解点这里 https://www.cnblogs.com/Gkeng,比我写的不知高到哪里去了。

Problem A:旋转子段

一对点反转后可以成为固定点,满足$a_i + i = a_j + j$.$a_i + i$可以确定一个反转区间的中心。

我们把每个$a_i + i$扔到桶里,这里用vector。枚举区间中心,按区间长度把每个桶内排序,扫一遍用区间内固定点个数更新答案。

这题没啥问题,实名谴责出题人假数据范围。

 1 #include <bits/stdc++.h>
 2 
 3 const int N = 1000005;
 4 int n, ori[N << 2], ans, sum[N << 2], pos;
 5 std::vector<int> v[N << 2];
 6 
 7 bool cmp(int x, int y) {
 8     return abs(pos - (x << 1)) < abs(pos - (y << 1));
 9 }
10 
11 signed main() {
12     scanf("%d", &n);
13     for (int i = 1; i <= n; i++) {
14         scanf("%d", &ori[i]);
15         sum[i] = sum[i - 1] + (ori[i] == i);
16         v[i + ori[i]].push_back(i);
17     }
18     for (int i = 2; i <= (n << 1); i++) {
19         if (v[i].empty()) continue;
20         pos = i;
21         std::sort(v[i].begin(), v[i].end(), cmp);
22         int j = 1;
23         for (auto k : v[i]) {
24             int l = k, r = i - k;
25             if (l > r) std::swap(l, r);
26             ans = std::max(ans, sum[l - 1] + sum[n] - sum[r] + j), j++;
27         }
28     }
29     return !printf("%d\n", ans);
30 }
A

Problem B:走格子

初看以为就是BFS,发现限制很多。

Portal可以直接等价于跑到离得最近的墙,建立Portal,就可以前往四个方向的任意一个墙。

想到暴力建图跑最短路。预处理墙的位置更好做一点。

本次考试以及OI生涯最大失误:把数据生成器错交到了OJ上。。。。。

我都不知道我的脑子里都在想点啥。。。。。。。。

以后提交之前必须check一下,100分白丢太痛苦,Rank 2 -> Rank 35

 1 #include <bits/stdc++.h>
 2 #define id(x, y) ((x - 1) * m + y)
 3 
 4 const int N = 500005, M = 505;
 5 int n, m, ecnt, head[N], st, ed, step[M][M], dis[N];
 6 int wall_l[M][M], wall_r[M][M], wall_u[M][M], wall_d[M][M];
 7 const int dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, 1, -1};
 8 char matrix[M][M];
 9 struct Edge {int to, nxt, val;} e[N << 3];
10 std::queue<std::pair<int, int> > q;
11 bool vis[N];
12 
13 inline void addedge(int f, int to, int val) {
14     e[++ecnt] = {to, head[f], val}, head[f] = ecnt;
15 }
16 
17 void link(int x, int y) {
18     if (matrix[x][y] != '.') return;
19     if (matrix[x][y + 1] == '.') addedge(id(x, y), id(x, y + 1), 1), 
20         addedge(id(x, y + 1), id(x, y), 1);;
21     if (matrix[x + 1][y] == '.') addedge(id(x, y), id(x + 1, y), 1),
22         addedge(id(x + 1, y), id(x, y), 1);
23     if (wall_l[x][y] != id(x, y)) addedge(id(x, y), wall_l[x][y], step[x][y]);
24     if (wall_r[x][y] != id(x, y)) addedge(id(x, y), wall_r[x][y], step[x][y]);
25     if (wall_u[x][y] != id(x, y)) addedge(id(x, y), wall_u[x][y], step[x][y]);
26     if (wall_d[x][y] != id(x, y)) addedge(id(x, y), wall_d[x][y], step[x][y]);
27 }
28 
29 void Dij() {
30     memset(dis, 0x3f, sizeof(dis));
31     memset(vis, 0, sizeof(vis));
32     std::priority_queue<std::pair<int, int> > que;
33     dis[st] = 0;
34     que.push(std::make_pair(0, st));
35     while (!que.empty()) {
36         int x = que.top().second;
37         que.pop();
38         if (vis[x]) continue;
39         vis[x] = 1;
40         for (int i = head[x], y = e[i].to; i; i = e[i].nxt, y = e[i].to) {
41             if (dis[y] > dis[x] + e[i].val) {
42                 dis[y] = dis[x] + e[i].val;
43                 if (!vis[y]) que.push(std::make_pair(-dis[y], y));
44             }
45         }
46     }
47 }
48 
49 signed main() {
50     scanf("%d%d", &n, &m);
51     for (int i = 1; i <= n; i++) {
52         scanf("%s", matrix[i] + 1);
53         for (int j = 1; j <= m; j++) {
54             if (matrix[i][j] == 'C') matrix[i][j] = '.', st = id(i, j);
55             else if (matrix[i][j] == 'F') matrix[i][j] = '.', ed = id(i, j);
56             else if (matrix[i][j] == '#') q.push(std::make_pair(i, j));
57         }
58     }
59     
60     while (!q.empty()) {
61         int x = q.front().first, y = q.front().second;
62         q.pop();
63         for (int i = 0; i <= 3; i++) {
64             int xx = x + dx[i], yy = y + dy[i];
65             if (matrix[xx][yy] == '.' && !step[xx][yy]) {
66                 step[xx][yy] = step[x][y] + 1;
67                 q.push(std::make_pair(xx, yy));
68             }
69         }
70     }
71 
72     for (int i = 1; i <= n; i++) {
73         for (int j = 1; j <= m; j++) {
74             if (matrix[i][j] != '.') continue;
75             if (matrix[i][j - 1] == '#') wall_l[i][j] = id(i, j);
76             else wall_l[i][j] = wall_l[i][j - 1];
77             if (matrix[i - 1][j] == '#') wall_u[i][j] = id(i, j);
78             else wall_u[i][j] = wall_u[i - 1][j];
79         }
80     }
81     
82     for (int i = n; i >= 1; i--) {
83         for (int j = m; j >= 1; j--) {
84             if (matrix[i][j] != '.') continue;
85             if (matrix[i][j + 1] == '#') wall_r[i][j] = id(i, j);
86             else wall_r[i][j] = wall_r[i][j + 1];
87             if (matrix[i + 1][j] == '#') wall_d[i][j] = id(i, j);
88             else wall_d[i][j] = wall_d[i + 1][j];
89         }
90     }
91 
92     for (int i = 1; i <= n; i++)
93         for (int j = 1; j <= m; j++) link(i, j);
94 
95     Dij();
96     if (dis[ed] == 0x3f3f3f3f) puts("no");
97     else printf("%d\n", dis[ed]);
98     return 0;
99 }
B

Problem C:柱状图

$O(N^3)$暴力很好想,枚举位置,枚举高度,暴力计算,考场时间剩太少&贪正解,甚至这玩意都没打。

$O(N^2)$需要动动脑子:我们要得到一个等差数列,可以直接给每一项减掉一个等差数列,再把它填平。可以想到填到处理后的中位数是最优的。

它过不去。瓶颈在于答案的计算。可以去打那个树状数组的正解,把内层的N优化到log,我直接用退火优化掉了外层的N,优化到O(玄学)。

一些人对退火有争议,我无法理解。用退火也没有什么问题,它和三分二分一样都是优化复杂度的工具,不存在什么骗AC的事情。而且本题答案(你原来要二分的那个东西,不是退火退的那个东西)必定单谷,这势必保证了退火实际效率能够吊打正解。

爱说啥说啥吧,hhh。

 1 #include <bits/stdc++.h>
 2 #define ll long long
 3 
 4 const double eps = 0.1;
 5 const int N = 100005;
 6 int n;
 7 ll x[N], tmp[N], tmppos, nowpos, tmpans, nowans = 0x3f3f3f3f3f3f3f3f;
 8 double T = 100000;
 9 
10 ll calc(int pos) {
11     ll mx = std::max(n - pos, pos - 1);
12     for (int i = 1; i <= n; i++) 
13         tmp[i] = x[i] - mx + abs(i - pos);
14     int mid = (1 + n) >> 1;
15     ll ret = 0, mdzz = 0;
16     std::nth_element(tmp + 1, tmp + mid, tmp + n + 1);
17     mdzz = tmp[mid] > 0 ? tmp[mid] : 1;
18     for (int i = 1; i <= n; i++) 
19         ret += abs(mdzz - tmp[i]);
20     return ret;
21 }
22 
23 signed main() {
24     srand(clock() + time(0));
25     scanf("%d", &n);
26     for (int i = 1; i <= n; i++)
27         scanf("%lld", &x[i]);
28     while (T > eps) {
29         tmppos = ((int) (nowpos + (int) (T * ((double) rand()/ (double) RAND_MAX) * (rand() % 2 ? 1 : -1)) % n + n)) % n + 1;
30         tmpans = calc(tmppos);
31         ll delta = tmpans - nowans;
32         if (delta < 0) 
33              nowans = tmpans, nowpos = tmppos;
34         else if (exp((double) -delta / T) * RAND_MAX > rand())
35             nowpos = tmppos;
36         T *= 0.976;
37     }
38     printf("%lld\n", nowans);
39     return 0;
40 }
C

 

posted @ 2019-08-09 14:12  Gekoo  阅读(168)  评论(4编辑  收藏  举报