1. 程式人生 > >Educational Codeforces Round 55 (Rated for Div. 2) Solution

Educational Codeforces Round 55 (Rated for Div. 2) Solution

A. Vasya and Book

Solved.

三種方式取$Min$

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define ll long long
 5 #define INF 0x3f3f3f3f3f3f3f3f
 6 int t;
 7 ll n, x, y, d;
 8 
 9 ll calc(ll x)
10 {
11     return x % d == 0 ? x / d : x / d + 1;
12 }
13 
14 int main()
15 {
16     scanf("
%d", &t); 17 while (t--) 18 { 19 scanf("%lld%lld%lld%lld", &n, &x, &y, &d); 20 ll res = INF; 21 if ((abs(y - x)) % d == 0) res = min(res, (abs(y - x) / d)); 22 if ((y - 1) % d == 0) res = min(res, calc(x) + (y - 1) / d); 23 if ((n - y) % d == 0
) res = min(res, calc(n - x) + (n - y) / d); 24 if (res == INF) res = -1; 25 printf("%lld\n", res); 26 } 27 return 0; 28 }
View Code

 

B. Vova and Trophies

Solved.

合併相同種類,再判斷是否有單獨的S使得替換掉它合併後得到更優解

 1 #include <bits/stdc++.h>
 2 using namespace std;
3 4 #define N 100010 5 #define pii pair <int, int> 6 int n, m; 7 char s[N]; 8 pii a[N]; 9 10 int main() 11 { 12 while (scanf("%d", &n) != EOF) 13 { 14 scanf("%s", s + 1); 15 int tot = s[1] == 'G', m = 0, tmp = 1; 16 for (int i = 2; i <= n; ++i) 17 { 18 tot += s[i] == 'G'; 19 if (s[i] != s[i - 1]) 20 { 21 a[++m] = pii(tmp, s[i] == 'G'); 22 tmp = 0; 23 } 24 ++tmp; 25 } 26 a[++m] = pii(tmp, s[n] != 'G'); 27 int res = 0; 28 for (int i = 1; i <= m; ++i) 29 { 30 if (a[i].second == 0) 31 res = max(res, min(tot, a[i].first + 1)); 32 else if (i != 1 && i != m && a[i].first == 1) 33 res = max(res, min(tot, a[i - 1].first + 1 + a[i + 1].first)); 34 } 35 printf("%d\n", res); 36 } 37 return 0; 38 }
View Code

 

C. Multi-Subject Competition

Solved.

題意:

有一個多學科競賽,一名隊員只會一門學科

派出去的隊伍對於每個要參加的學科其參加的人數要相等

並且每個隊員對於其會的那門學科有一個技能值

求如何派出隊伍參加學科使得隊伍中所有隊員的技能值總和最大。

思路:

列舉要參加的學科派出的隊員數,網上列舉,不符合條件的學科消除影響,每名隊員只會遍歷一次

時間複雜度$O(n)$

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define N 100010
 5 int n, m;
 6 vector <int> v[N];
 7 int tot[N];
 8 queue <int> q;
 9 
10 int main()
11 {
12     while (scanf("%d%d", &n, &m) != EOF)
13     {
14         for (int i = 1; i <= m; ++i) v[i].clear(); 
15         memset(tot, 0, sizeof tot);
16         while (!q.empty()) q.pop();
17         for (int i = 1, s, r; i <= n; ++i)
18         {
19             scanf("%d%d", &s, &r);
20             v[s].push_back(r);
21         }
22         for (int i = 1; i <= m; ++i) sort(v[i].rbegin(), v[i].rend());
23         for (int i = 1; i <= m; ++i) q.push(i); 
24         int res = 0, tmp = 0;
25         for (int i = 1; ; ++i)
26         {
27             if (q.empty()) break;
28             for (int j = 1, len = q.size(); j <= len; ++j)
29             {
30                 int top = q.front(); q.pop();
31                 tmp -= tot[top]; 
32                 if (v[top].size() < i) 
33                     continue;
34                 tot[top] += v[top][i - 1];
35                 if (tot[top] <= 0) continue;
36                 tmp += tot[top];    
37                 q.push(top);
38             }
39             res = max(res, tmp);
40         }
41         printf("%d\n", res);
42     }
43     return 0; 
44 }
View Code

 

D. Maximum Diameter Graph

Solved.

題意:

給出一個n,和每個點最大的度數,構造一棵樹,使得每個點的度數不超過最大度數,並且直徑最長

思路:

如果所有點的度數之和小於$2 * (n - 1)$ 那麼就不可以構造

否則將所有度數$>= 2的點放到直徑上,再兩邊新增一個度為1的點(如果有)$

$剩下的點就連到這條直徑上還有度數剩餘的點上$

 

n給的好小,好懷疑自己的做法,當時。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define N 510
 5 int n, a[N];
 6 vector <int> l, r;
 7 
 8 int main()
 9 {
10     while (scanf("%d", &n) != EOF)
11     {
12         int sum = 0;
13         l.clear(), r.clear();
14         for (int i = 1; i <= n; ++i) 
15         {
16             scanf("%d", a + i);
17             sum += a[i];
18             if (a[i] > 1) l.push_back(i);
19             else r.push_back(i); 
20         }
21         if (sum < 2 * (n - 1)) puts("NO");
22         else
23         {
24             if (!r.empty()) l.insert(l.begin(), r.end()[-1]), r.pop_back();
25             if (!r.empty()) l.push_back(r.end()[-1]), r.pop_back();
26             printf("YES %d\n", (int)l.size() - 1);
27             printf("%d\n", n - 1);
28             for (int i = 1, len = l.size(); i < len; ++i) printf("%d %d\n", l[i], l[i - 1]), --a[l[i]], --a[l[i- 1]]; 
29             for (int i = 0, j = 0, len1 = l.size(), len2 = r.size(); i < len2; ++i)
30             {
31                 while (a[l[j]] == 0) ++j;
32                 --a[l[j]];
33                 printf("%d %d\n", r[i], l[j]);
34             }
35         }
36     }
37     return 0;
38 }
View Code

 

E. Increasing Frequency

Solved.

題意:

給出一個n個數,可以選取一段$[l, r], 使得區間內所有數都+k

$求最多進行一次這樣的操作,使得最後$a_i == c的個數最多$

求這個最多的個數

思路:

顯然一個區間的貢獻這個區間內相同數字最大的個數加上區間外c的個數,然後這樣區間列舉就是$O(n^2)$

我們可以考慮,列舉$a_i$ 即要把哪些數字變成$c$

那麼這時候,所有不是$c也不是a_i 的數字就沒有用$ 不妨把它們單獨拿出來考慮(類似於虛樹思想)

假設$L[i], R[i] 表i左邊的c的個數 和 i 右邊的c的個數$

那麼我假設序列中有$x個a(a 為列舉的a_i)$

$L[1], R[1], ...  L[x], R[x]$

我們$需要找一個以後 x, y 使得 R[y] + (y - x + 1) + L[x] 最大$

$那麼可以列舉x ,然後即找一個最大的 (y - x + 1) + R[y]$ 

這個可以用線段樹維護。

發現常數項是遞增的,建樹的時候就可以給它,每次更新的時候,相當於後面的每一個都減一

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define N 500010
 5 int n, c, a[N], dpl[N], dpr[N];
 6 vector <int> v[N];
 7 
 8 namespace SEG
 9 {
10     int Max[N << 2], lazy[N << 2];
11     void pushup(int id) { Max[id] = max(Max[id << 1], Max[id << 1 | 1]); }
12     void build(int now, int id, int l, int r)
13     {
14         Max[id] = lazy[id] = 0;
15         if (l == r)
16         {
17             Max[id] = l + dpr[v[now][l - 1]];
18             return;
19         }
20         int mid = (l + r) >> 1;
21         build(now, id << 1, l, mid);
22         build(now, id << 1 | 1, mid + 1, r);
23         pushup(id);
24     }
25     void pushdown(int id)
26     {
27         if (!lazy[id]) return;
28         lazy[id << 1] += lazy[id];
29         Max[id << 1] += lazy[id];
30         lazy[id << 1 | 1] += lazy[id];
31         Max[id << 1 | 1] += lazy[id];
32         lazy[id] = 0;
33     }
34     void update(int id, int l, int r, int ql, int qr)
35     {    
36         if (l >= ql && r <= qr)
37         {
38             --Max[id];
39             --lazy[id];
40             return;
41         }
42         int mid = (l + r) >> 1;
43         pushdown(id);
44         if (ql <= mid) update(id << 1, l, mid, ql, qr);
45         if (qr > mid) update(id << 1 | 1, mid + 1, r, ql, qr);
46         pushup(id);
47     }
48     int query(int id, int l, int r, int ql, int qr)
49     {
50         if (l >= ql && r <= qr) return Max[id];
51         int mid = (l + r) >> 1;
52         pushdown(id);
53         int res = 0;
54         if (ql <= mid) res = max(res, query(id << 1, l, mid, ql, qr));
55         if (qr > mid) res = max(res, query(id << 1 | 1, mid + 1, r, ql, qr));
56         return res;
57     }
58 }
59 
60 void init()
61 {
62     for (int i = 1; i <= 500000; ++i) v[i].clear();
63 }
64 
65 int main()
66 {
67     while (scanf("%d%d", &n, &c) != EOF)
68     {
69         init();
70         for (int i = 1; i <= n; ++i) scanf("%d", a + i), v[a[i]].push_back(i);
71         int tmp = 0;
72         for (int i = 1; i <= n; ++i)
73         {
74             dpl[i] = tmp;
75             tmp += a[i] == c; 
76         }
77         tmp = 0;
78         for (int i = n; i >= 1; --i)
79         {
80             dpr[i] = tmp;
81             tmp += a[i] == c;
82         }
83         int res = 0;
84         for (int i = 1; i <= 500000; ++i) if (v[i].size())
85         {
86             int len = v[i].size();
87             SEG::build(i, 1, 1, len);
88             for (int j = 0; j < len; ++j)
89             {
90                 res = max(res, dpl[v[i][j]] + SEG::query(1, 1, len, j + 1, len));
91                 SEG::update(1, 1, len, j + 1, len);
92             } 
93         }    
94         printf("%d\n", res);
95     }
96     return 0; 
97 }
View Code

 

F. Speed Dial

Unsolved.

 

 

G. Petya and Graph

Unsolved.