Avito Cool Challenge 2018 Solution

A. Definite Game

签.

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int main()
 5 {
 6     int a;
 7     while (scanf("%d", &a) != EOF)
 8     {
 9         [](int x) 
10         {
11             for (int i = x - 1; i >= 1; --i) if (x % i)
12             {
13                 printf("%d
", x - i);
14                 return;
15             }
16             printf("%d
", x);
17         }(a);
18     }
19     return 0;
20 }
View Code

B. Farewell Party

签。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define N 100010
 5 int n, a[N], b[N], cnt[N];
 6 vector <int> v[N];
 7 int ans[N];
 8 
 9 bool ok()
10 {
11     for (int i = 1; i <= n; ++i) if (!v[i].empty() && v[i].size() != i)
12         return false;
13     return true;
14 }
15 void solve()    
16 {    
17     int cnt = 0;
18     for (int i = 1; i <= n; ++i) v[i].clear();
19     for (int i = 1; i <= n; ++i) 
20     {
21         int id = n - a[i];
22         if (v[id].size() == id) 
23         {
24             ++cnt;
25             for (auto it : v[id]) ans[it] = cnt;
26             v[id].clear();
27         }
28         v[id].push_back(i);
29     }
30     if (!ok())
31     {
32         puts("Impossible");
33         return;
34     }
35     else
36     {
37         for (int i = 1; i <= n; ++i) if (!v[i].empty()) 
38         {
39             ++cnt;
40             for (auto it : v[i])
41                 ans[it] = cnt;
42         }
43         puts("Possible");
44         for (int i = 1; i <= n; ++i) printf("%d%c", ans[i], " 
"[i == n]);
45     }
46 }
47 
48 int main()
49 {
50     while (scanf("%d", &n) != EOF)
51     {
52         for (int i = 1; i <= n; ++i) scanf("%d", a + i);
53         solve();
54     }
55     return 0;
56 }
View Code

C. Colorful Bricks

Upsolved.

题意:

有$一行n个方格,m种颜色,恰好有k个方块与它左边方块的颜色不同$

求方案数

思路:

$dp[i][j] 表示到第i个方格,有j个方块与左边方块颜色不同的方案数$

转移有

$dp[i + 1][j] += dp[i][j]$

$dp[i + 1][j + 1] += dp[i][j] * (m - 1)$

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define ll long long
 5 #define N 2010
 6 const ll MOD = (ll)998244353;
 7 int n, m, k;
 8 ll f[N][N];
 9 
10 int main()
11 {
12     while (scanf("%d%d%d", &n, &m, &k) != EOF)
13     {
14         memset(f, 0, sizeof f);
15         f[1][0] = m;
16         for (int i = 2; i <= n; ++i)
17         { 
18             for (int j = 0; j <= min(i - 2, k); ++j)
19             {
20                 f[i][j] = (f[i][j] + f[i - 1][j]) % MOD;
21                 f[i][j + 1] = (f[i][j + 1] + f[i - 1][j] * (m - 1) % MOD) % MOD;          
22             }
23         }
24         printf("%lld
", f[n][k]);
25     }
26     return 0;
27 }
View Code

D. Maximum Distance

Upsolved.

题意:

有一张图

定义一条路径的长度的路径上边权最大值

定义两点距离为两点之间最短路径

有一些特殊点,要对所有特殊点求离它最远的特殊点

思路:

我们考虑一条边所连接的两个连通块里,如果这两个连通块里都有特殊点

那么这条边的权值就可以用于更新特殊点的答案

其实就是一个求最小生成树的过程,先按边权排序

要注意的是不是求整个图的最小生成树,而是所有特殊点的最小生成树

其实是最小瓶颈生成树.

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define N 100010
 5 int n, m, k;
 6 struct node
 7 {
 8     int u, v, w;
 9     void scan() { scanf("%d%d%d", &u, &v, &w); }
10     bool operator < (const node &other) const { return w < other.w; }
11 }edge[N];
12 
13 int pre[N], cnt[N];
14 int find(int x) { return pre[x] == 0 ? x : pre[x] = find(pre[x]); }
15 int Kruskal()
16 {
17     sort(edge + 1, edge + 1 + m);
18     for (int i = 1; i <= m; ++i)
19     {
20         int u = edge[i].u, v = edge[i].v, w = edge[i].w;
21         int fu = find(u), fv = find(v); 
22         if (fu == fv) continue;
23         cnt[fv] += cnt[fu]; 
24         pre[fu] = fv;
25         if (cnt[fv] == k) return w;  
26     }
27 }
28 
29 int main()
30 {
31     while (scanf("%d%d%d", &n, &m, &k) != EOF)
32     {
33         memset(pre, 0, sizeof pre);
34         memset(cnt, 0, sizeof cnt); 
35         for (int i = 1, x; i <= k; ++i) scanf("%d", &x), cnt[x] = 1;
36         for (int i = 1; i <= m; ++i) edge[i].scan();
37         int res = Kruskal();
38         for (int i = 1; i <= k; ++i) printf("%d%c", res, " 
"[i == k]);
39     }
40     return 0;
41 }
View Code

E. Missing Numbers

Upsolved.

题意:

有$n个数,给出a_2, a_4 cdots a_n$

$n是偶数,提供a_1, a_3 cdots a_{n - 1}$

使得

$所有前缀和都是平方数$

思路:

考虑$n = 2的时候$

$我们令b^2 = a_1 + a_2$

$a^2 = a_1$

那么有

$b^2 - a^2 = (b + a) cdot (b - a) = a_2$

$我们将a_2 拆成 p cdot q 的形式$

$令p >= q$

$那么有  b + a = p, b - a = q$

$解方程有 b = frac{p + q}{2}$

$发现一限制条件 p, q的奇偶性要相同$

$那么a_1 = (frac{p + q}{2})^2 - a_2$

那么如果有多解 我们取$a_1最小的$

$因为当n >= 2的情况也可以同样这样推下去,会发现前面的项越小越好$

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define ll long long
 5 #define N 100010
 6 int n;
 7 ll x[N];
 8 vector <int> vec[N << 1];
 9 
10 void init()
11 {
12     for (int i = 1; i <= 450; ++i)
13         for (int j = i * i; j <= 200000; j += i)
14             vec[j].push_back(i);
15 }
16     
17 int main()
18 {
19     init();
20     while (scanf("%d", &n) != EOF)
21     {
22         for (int i = 2; i <= n; i += 2) scanf("%lld", x + i);
23         bool flag = true; 
24         ll base = 0;
25         for (int i = 1; i <= n; i += 2)
26         {
27             base += x[i + 1];
28             int limit = sqrt(x[i + 1]);
29             ll res = (ll)1e18; 
30             ll p, q;
31             for (auto j : vec[x[i + 1]])                
32                 if ((j % 2) == ((x[i + 1] / j) % 2))
33                 {    
34                     p = j, q = (x[i + 1] / j);
35                     ll tot = (p + q) / 2;
36                     tot *= tot;
37                     if (tot > base)
38                         res = min(res, tot - base);
39                 }
40             if (res <= (ll)1e13) 
41             {
42                 x[i] = res;
43                 base += res;
44             }
45             else
46             {
47                 flag = false;
48                 break;
49             }
50         }
51         if (!flag) puts("No");
52         else
53         {
54             puts("Yes");
55             for (int i = 1; i <= n; ++i)
56                 printf("%lld%c", x[i], " 
"[i == n]);
57         }
58     }
59     return 0;
60 }
View Code
原文地址:https://www.cnblogs.com/Dup4/p/10332497.html