ZROI 2019 寒假省选线下自闭赛

题目地址

预计得分:$20+10+60=90$

实际得分:$20+10+20=50$

 

自闭了,,,T3想出K=1的做法然后写炸,还要比暴力低10分

不过这次考试倒是给了我一个教训,就是在考虑复杂度的时候千万不能感性理解

多花点时间去算一下具体的复杂度,不会算也要构造数据跑一下

不要动不动就觉得这个东西是$O(nlogn)$的,有时候一不注意就变成了$O(n^2)$

 

$T1:$

20分直接模拟即可

对于这种题,一般有一个套路就是枚举长度(就是j-i+1),然后去统计答案

考虑优化统计答案的速度(就是不要每次都去找具体的i,j,k,然后再ans++)

假如有一个串:abaada,如果我们已经知道了ab和aa可以拼接,现在我们又知道了aa和da可以拼接

那显然ab,aa,da三个串也可以拼接,于是ans+=2

考虑怎么快速去发现一段子串s[i...j]是否能与s[i+len...j+len]能够拼接(即至多只有一个位置不同)

我们可以$O(n)$的处理出一个数组S,S[i]表示s[i]是否与s[i+len]不相同

如果某段S[i..j]之和小于等于1的话,就说明这段能够和s[i+len...j+len]相拼接(利用前缀和即可快速知道区间和)

 然后数组dp[i]则表示s[i-len+1...i]能和几段拼接,于是我们可以就可以在$O(\frac{n}{2}*n)$的时间内求出答案

对于那20分的随机部分,只需将枚举的长度限制得比较小即可,比如50或100

满分算法先咕一下,搞懂了再说

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 char str[100010];
 5 int n, maxx, s[100010], dp[100010];
 6 long long ans;
 7 
 8 int main()
 9 {
10     scanf("%s", str + 1);
11     n = strlen(str + 1);
12     maxx = (n <= 5000 ? n >> 1 : 100);
13     for(int len = 2; len <= maxx; ++len)
14     {
15         memset(s, 0, sizeof(s));
16         memset(dp, 0, sizeof(dp));
17         for(int i = 1; i <= n - len; ++i) s[i] = (str[i] != str[i + len]);
18         for(int i = 1; i <= n - len; ++i) s[i] += s[i - 1];
19         for(int i = len; i <= n - len; ++i)
20             if(s[i] - s[i - len] <= 1) 
21                 dp[i] = dp[i - len] + 1, ans += dp[i];
22     }
23     printf("%lld\n", ans);
24     return 0;
25 }

 

$T2:$

期望???多项式???

反正都不会,写下十分暴力走人

会了再来写(咕咕)

 

$T3:$

看着题目里的最小生成树,我突然想到了当年在XJOI上考过的那个题,就是很多个点的完全图(1e5)求最小生成树(虽然当时并不会还是机房dalao教我的)

k=1的情况差不多也是同理,我们考虑做Kruskal的过程,是要从小到大的枚举边,然后连满m-1条边(因为line graph是m个点)

根据题意,line graph里的边就是原图中的公共点,于是我们将原图的点排个序从小到大枚举

如果当前这个点的出度超过1,说明在line graph中肯定有一条边的权值是这个点的点权,于是我们就把这条边所代表的两个集合合并即可

用并查集维护,复杂度大概是$O(n+m)$加并查集复杂度(可能不是?反正我不怎么会算,能过就对了)

k=2的情况可以先暴力做一遍,然后按照k=1的情况处理

这样就有60分的好成绩了,什么你说100分??

先咕着把,会了再说

代码(可能比较长,因为在考场上改来改去的):

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 
  4 namespace solve_bf
  5 {
  6     struct Edge
  7     {
  8         int from, to, val;
  9         bool operator < (const Edge &x) const
 10         {
 11             return val < x.val;
 12         };
 13     }e[2000010];
 14     int point[2000010];
 15 
 16     int n, m, k, fa[2000010];
 17     
 18     int Get(int x)
 19     {
 20         if(x == fa[x]) return x;
 21         return fa[x] = Get(fa[x]);
 22     }
 23 
 24     long long Kruskal()
 25     {
 26         long long ans = 0;
 27         for(int i = 1; i <= n; ++i) fa[i] = i;
 28         sort(e + 1, e + 1 + m);
 29         for(int i = 1; i <= m; ++i)
 30         {
 31             int f1 = Get(e[i].from);
 32             int f2 = Get(e[i].to);
 33             if(f1 == f2) continue;
 34             fa[f1] = f2;
 35             ans += e[i].val;
 36         }
 37         return ans;
 38     }
 39     
 40     void solve(int a, int b, int c)
 41     {
 42         n = a, m = b, k = c;
 43         for(int i = 1; i <= n; ++i) scanf("%d", &point[i]);
 44         for(int i = 1; i <= m; ++i) scanf ("%d %d %d", &e[i].from, &e[i].to, &e[i].val);
 45         printf("%lld\n", Kruskal());
 46     }
 47 }
 48 
 49 namespace solve_one
 50 {
 51     struct Point
 52     {
 53         int id, val;
 54         bool operator < (const Point &x) const
 55         {
 56             return val < x.val;
 57         };
 58     }p[2000010];
 59 
 60     vector<int> G[2000010];
 61     int n, m, k, cnt, fa[2000010];
 62     long long ans;
 63 
 64     int Get(int x)
 65     {
 66         if(x == fa[x]) return x;
 67         return fa[x] = Get(fa[x]);
 68     }
 69 
 70     void solve(int a, int b, int c)
 71     {
 72         n = a, m = b, k = c;
 73         for(int i = 1; i <= n; ++i)
 74         {
 75             p[i].id = i;
 76             scanf("%d", &p[i].val);
 77         }
 78         for(int i = 1; i <= m; ++i)
 79         {
 80             int u, v, z;
 81             scanf("%d %d %d", &u, &v, &z);
 82             G[u].push_back(i);
 83             G[v].push_back(i);
 84         }
 85         for(int i = 1; i <= m; ++i) fa[i] = i;
 86         sort(p + 1, p + 1 + n);
 87         for(int i = 1; i <= n; ++i)
 88             if(G[p[i].id].size() > 1)
 89             {
 90                 int id = p[i].id;
 91                 for(int j = 0; j < G[id].size() - 1; ++j)
 92                 {
 93                         int f1 = Get(G[id][j]);
 94                         int f2 = Get(G[id][j + 1]);
 95                         if(f1 == f2) continue;
 96                         fa[f1] = f2;
 97                         ans += p[i].val;
 98                         if(++cnt == m - 1) break;
 99                     if(cnt == m - 1) break;
100                 }
101                 if(cnt == m - 1) break;
102             }
103         printf("%lld\n", ans);
104     }
105 }
106 
107 namespace solve_two
108 {
109     struct Edge
110     {
111         int from, to, val;
112         bool operator < (const Edge &x) const
113         {
114             return val < x.val;
115         };
116     }e[2000010], e2[2000010];
117     int point[2000010], point2[2000010];
118 
119     int n, m, k, cnt, fa[2000010];
120     long long ans;
121 
122     int Get(int x)
123     {
124         if(x == fa[x]) return x;
125         return fa[x] = Get(fa[x]);
126     }
127 
128     int Check(int a, int b, int c, int d)
129     {
130         if(a == b || a == c || a == d) return a;
131         if(b == c || b == d) return b;
132         if(c == d) return c;
133         return -1;
134     }
135 
136     void solves()
137     {
138         int new_n = m, new_m = 0;
139         for(int i = 1; i <= new_n; ++i) point2[i] = e[i].val;
140         for(int i = 1; i <= new_n; ++i)
141             for(int j = i + 1; j <= new_n; ++j)
142             {
143                 int id = Check(e[i].from, e[i].to, e[j].from, e[j].to);
144                 if(id == -1) continue;
145                 e2[++new_m] = (Edge){i, j, point[id]};
146             }
147         n = new_n, m = new_m;
148     }
149     
150     struct Point
151     {
152         int id, val;
153         bool operator < (const Point &x) const
154         {
155             return val < x.val;
156         };
157     }p[2000010];
158     vector<int> G[2000010];
159     
160     void solve(int a, int b, int c)
161     {
162         n = a, m = b, k = c;
163         for(int i = 1; i <= n; ++i) scanf("%d", &point[i]);
164         for(int i = 1; i <= m; ++i) scanf ("%d %d %d", &e[i].from, &e[i].to, &e[i].val);
165         solves();
166         for(int i = 1; i <= n; ++i)
167         {
168             p[i].id = i;
169             p[i].val = point2[i];
170         }
171         for(int i = 1; i <= m; ++i)
172         {
173             G[e2[i].from].push_back(i);
174             G[e2[i].to].push_back(i);
175         }
176         for(int i = 1; i <= m; ++i) fa[i] = i;
177         sort(p + 1, p + 1 + n);
178         for(int i = 1; i <= n; ++i)
179             if(G[p[i].id].size() > 1)
180             {
181                 int id = p[i].id;
182                 for(int j = 0; j < G[id].size() - 1; ++j)
183                 {
184                         int f1 = Get(G[id][j]);
185                         int f2 = Get(G[id][j + 1]);
186                         if(f1 == f2) continue;
187                         fa[f1] = f2;
188                         ans += p[i].val;
189                         if(++cnt == m - 1) break;
190                     if(cnt == m - 1) break;
191                 }
192                 if(cnt == m - 1) break;
193             }
194         printf("%lld\n", ans);
195     }
196 }
197 
198 int main()
199 {
200     int n, m, k;
201     scanf("%d %d %d", &n, &m, &k);
202     if(k == 1) solve_one::solve(n, m, k);
203     else if(k == 2) solve_two::solve(n, m, k);
204     else solve_bf::solve(n, m, k);
205     return 0;
206 }

 

posted @ 2019-02-11 17:11  Aegir  阅读(260)  评论(0编辑  收藏  举报