正睿20NOIp前冲刺day9

估分:20+45+30=95

实际:0+0+15=15

T1:

  数组开大了,初始化超时了

  遍历一遍数组当答案的右端点,线段树维护左端点对应的答案,每次遍历时更新一下答案即可

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<vector>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 
 8 #define pb push_back
 9 
10 typedef long long LL;
11 
12 const int N = 1000010;
13 
14 int n, m;
15 LL col[N], v[N];
16 LL lazy[N << 2], tr[N << 2];
17 vector<int> id[N];
18 
19 void pushup(int q)
20 {
21     tr[q] = max(tr[q << 1], tr[q << 1 | 1]);
22 }
23 
24 void pushdown(int q)
25 {
26     if (!lazy[q]) return;
27     lazy[q << 1] += lazy[q], tr[q << 1] += lazy[q];
28     lazy[q << 1 | 1] += lazy[q], tr[q << 1 | 1] += lazy[q];
29     lazy[q] = 0;
30 }
31 
32 void modify(int q, int l, int r, int L, int R, LL x)
33 {
34     if (L <= l && r <= R)
35     {
36         lazy[q] += x;
37         tr[q] += x;
38         return;
39     }
40 
41     pushdown(q);
42     int mid = (l + r) >> 1;
43     if (L <= mid) modify(q << 1, l, mid, L, R, x);
44     if (R > mid) modify(q << 1 | 1, mid + 1, r, L, R, x);
45     pushup(q);
46 }
47 
48 int main()
49 {
50     scanf("%d%d", &n, &m);
51     for (int i = 1; i <= m; i++) id[i].pb(0);
52     for (int i = 1; i <= n; i++) scanf("%lld", &col[i]);
53     for (int i = 1; i <= m; i++) scanf("%lld", &v[i]);
54     LL ans = 0;
55     for (int i = 1; i <= n; i++)
56     {
57         int c = col[i];
58         int k = id[c].size(), ed = id[c].back();
59         if (k > 1) modify(1, 1, n, id[c][k - 2] + 1, ed, -v[c]);
60         modify(1, 1, n, ed + 1, i, v[c]);
61         id[c].pb(i);
62         ans = max(ans, tr[1]);
63     }
64     printf("%lld", ans);
65 }
View Code

T2:

  没判-1的情况,丢45分

  与原点直接距离相同的有这些点:

 

 

  把坐标轴旋转45°后这些点变成了这个样子

 

 

  可以发现直接距离||x1-x2|-|y1-y2||在坐标轴旋转45°后变成了min(|x1-x2|,|y1-y2|)

  然后就求每个点旋转后的坐标,如图:

 

 

  x1=r cos(a+b)  ,  y1=r sin(a+b)

  根据和差角公式,得到:

  x1=r cos(a)cos(b) - r sin(a)sin(b) , y1=r sin(a)cos(b) + r cos(a)sin(b)

  因为 x2=r cos(b) , y2=r sin(b)

  所以 x1=x2 cos(a) - y2 sin(a) , y1=x2 sin(a) + y2 cos(a)

  又因为 a=45°

  所以 cos(a)=sin(a)=1/√2

  我们直接把坐标轴扩大√2倍就能直接把他消掉,所以一个点旋转后的坐标(x1,y1)就是(x-y,x+y)

  之后就统计答案(以下的x,y均为旋转后的坐标)

  按x排一个序,按y排一个序,然后都扫一遍,把能的出来的所有直接距离都放入r,然后最小的就是答案

  然后算方案数,把直接距离为0的点并查集并在一起,要是有两个点的最短距离是答案的话就把方案数加上他们所在的并查集的个数相乘的积。因为直接距离是min(|x1-x2|,|y1-y2|),所以若有两个点的x或y相等就把他们并在一起,为了方便,把一个点的x与y并在一起,当有点和他的x或y相等时,他们的x和y就并在一起,相当于两个点并在一起

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<set>
 4 #include<vector>
 5 #include<iostream>
 6 #include<algorithm>
 7 using namespace std;
 8 
 9 #define mp make_pair
10 #define pb push_back
11 
12 typedef pair<int, int> PII;
13 typedef long long LL;
14 
15 const int N = 1000010;
16 
17 int n;
18 int siz[N], fa[N];
19 vector<int> sx, sy;
20 set<PII> st;
21 
22 struct Node
23 {
24     int x, y, w;
25     Node() {}
26     Node(int x, int y, int w) :x(x), y(y), w(w) {}
27 };
28 vector<Node> dis;
29 
30 bool cmp(Node a, Node b) { return a.w < b.w; }
31 
32 inline int get1(int x) { return x + 200001; }
33 inline int get2(int x) { return x + 600002; }
34 
35 inline int find1(int x) { return fa[x] ? fa[x] = find1(fa[x]) : x; }
36 
37 inline void merge(int x, int y)
38 {
39     int a = find1(x), b = find1(y);
40     siz[a]++;
41     if (a == b) return;
42     fa[b] = a;
43     siz[a] += siz[b];
44 }
45 
46 int main()
47 {
48     scanf("%d", &n);
49     if (n == 1) puts("-1"), exit(0);
50     for (int i = 1; i <= n; i++)
51     {
52         int a, b;
53         scanf("%d%d", &a, &b);
54         int x = a + b, y = a - b;
55         merge(get1(x), get2(y));
56         sx.pb(x), sy.pb(y);
57     }
58 
59     sort(sx.begin(), sx.end());
60     sx.erase(unique(sx.begin(), sx.end()), sx.end());
61     sort(sy.begin(), sy.end());
62     sy.erase(unique(sy.begin(), sy.end()), sy.end());
63 
64     for (int i = 1; i < sx.size(); i++)
65     {
66         int x = find1(get1(sx[i - 1])), y = find1(get1(sx[i])), w = sx[i] - sx[i - 1];
67         if (x == y) continue;
68         dis.pb(Node(x, y, w));
69     }
70     for (int i = 1; i < sy.size(); i++)
71     {
72         int x = find1(get2(sy[i - 1])), y = find1(get2(sy[i])), w = sy[i] - sy[i - 1];
73         if (x == y) continue;
74         dis.pb(Node(x, y, w));
75     }
76 
77     if (dis.empty()) puts("-1"), exit(0);
78     sort(dis.begin(), dis.end(), cmp);
79     int ans = dis[0].w;
80     LL pro = 0;
81     for (auto i : dis)
82     {
83         if (i.w != ans) break;
84         int x = find1(i.x), y = find1(i.y);
85         if (x > y) swap(x, y);
86         if (st.count(mp(x, y))) continue;
87         st.insert(mp(x, y));
88         pro += 1ll * siz[x] * siz[y];
89     }
90     printf("%d\n%lld", ans, pro);
91 }
View Code

T3:

  取模出了点问题,少了15分

  没写完

 

总结:

  以后还是要多检查检查代码,总是出问题。这种关于坐标距离的题还是要多找规律。

  

posted on 2020-10-22 17:25  ArrogHie  阅读(140)  评论(0编辑  收藏  举报