1. 程式人生 > >Codeforces Round #539 (Div. 2)

Codeforces Round #539 (Div. 2)

return != sizeof 初始 include sting The rap auto

A. Sasha and His Trip

簽。

技術分享圖片
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int n, v;
 5 
 6 int main()
 7 {
 8     while (scanf("%d%d", &n, &v) != EOF)
 9     {
10         int res = 0;
11         if (v >= n - 1) res = n - 1;
12         else
13         {
14             res = v;
15 for (int i = 1, j = 2; i <= n - 1 - v; ++i, ++j) 16 res += j; 17 } 18 printf("%d\n", res); 19 } 20 return 0; 21 }
View Code

B. Sasha and Magnetic Machines

簽。

如果可以換無限次怎麽做?

技術分享圖片
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define
N 50010 5 vector <int> fac[110]; 6 int n, a[N], cnt[110]; 7 8 int main() 9 { 10 for (int i = 2; i <= 100; ++i) 11 { 12 fac[i].clear(); 13 for (int j = 2; j <= i; ++j) if (i % j == 0) 14 fac[i].push_back(j); 15 } 16 while (scanf("%d", &n) != EOF)
17 { 18 int res = 0; 19 memset(cnt, 0, sizeof cnt); 20 for (int i = 1; i <= n; ++i) 21 { 22 scanf("%d", a + i); 23 res += a[i]; 24 ++cnt[a[i]]; 25 } 26 int tot = res; 27 for (int i = 1; i <= 100; ++i) 28 { 29 for (int j = 1; j <= 100; ++j) if (cnt[i] && cnt[j] && i != j) 30 { 31 int tmp = i + j; 32 for (auto it : fac[i]) 33 res = min(res, tot - tmp + i / it + j * it); 34 } 35 } 36 for (int i = 1; i <= 100; ++i) if (cnt[i] >= 2) 37 { 38 int tmp = 2 * i; 39 for (auto it : fac[i]) 40 res = min(res, tot - tmp + i * it + i / it); 41 } 42 printf("%d\n", res); 43 } 44 return 0; 45 }
View Code

C. Sasha and a Bit of Relax

Solved.

題意:

有一個數列,找出多少個$(l, r) 使得 r - l + 1 是偶數 並且$

$a_l \oplus a_{l + 1} \oplus \cdots \oplus a_{mid} = a_{mid +1} \oplus a_{mid +2} \oplus \cdots \oplus a_r$

思路:

令$f[]表示前綴異或$

$那麽第二個條件用前綴異或來表示就是 f_r \oplus f_{mid} = f_{mid} \oplus f_{l - 1}$

其實就是統計有多少個$f_r 和 f_{l - 1} 相同,並且 r - l +1 是偶數$

技術分享圖片
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define ll long long
 5 #define N 300010
 6 #define M 1100000
 7 int n, a[N], sum[N];
 8 int cnt[M][2];
 9 
10 ll f(int n)
11 {
12     return 1ll * n * (n - 1) / 2;
13 }
14 
15 int main()
16 {
17     while (scanf("%d", &n) != EOF)
18     {
19         sum[0] = 0;
20         memset(cnt, 0, sizeof cnt);
21         ++cnt[0][0];
22         for (int i = 1; i <= n; ++i) 
23         {
24             scanf("%d", a + i);
25             sum[i] = sum[i - 1] ^ a[i];
26             ++cnt[sum[i]][i & 1]; 
27         }
28         ll res = 0;
29         for (int i = 0; i < (1 << 20); ++i)
30         {
31             res += f(cnt[i][0]) + f(cnt[i][1]);
32         }
33         printf("%lld\n", res);
34     }
35     return 0;
36 }
View Code

D. Sasha and One More Name

Solved.

題意:

給出一個回文串,可以將該回文串切成若幹段再任意拼接

使得拼接之後的串也是回文串並且不是原串

求最小的切割次數

思路:

首先可以考慮一次切割是否可行,可以$O(n^2)判斷$

$再考慮二次切割,如果二次切割不行,那麽次數再增加都不行$

$二次切割的情況,即將原串一分為二,在左邊找一個子串使得這個子串不是回文串$

$那麽把這個回文串倒置一下和右邊對應位置交換即可$

$首先我們考慮起點都是原串的起點,只需要枚舉子串的終點即可$

$因為如果存在某個子串它的起點不是初始起點使得它不是回文,那麽將起點移到初始起點,它也不是回文$

$再考慮如果找不到,那麽說明所有子串都是回文,這種情況就是所有字符都相等$

$當然如果原串長度是奇數,中間那個字符可以不用考慮$

技術分享圖片
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define N 5010
 5 char s[N];
 6 int len;
 7 
 8 bool ok(string s)
 9 {
10     int len = s.size();
11     for (int i = 0; i < len / 2; ++i)
12         if (s[i] != s[len - i - 1])
13             return false;
14     return true;
15 }
16 
17 bool same(string str)
18 {
19     for (int i = 0; i < len; ++i)
20         if (str[i] != s[i + 1])
21             return false;
22     return true;
23 }
24 
25 int solve()
26 {
27     len = strlen(s + 1);
28     for (int i = 1; i < len; ++i)
29     {
30         string tmp = "";
31         for (int j = i + 1; j <= len; ++j) tmp += s[j];
32         for (int j = 1; j <= i; ++j) tmp += s[j];
33         if (!same(tmp) && ok(tmp)) return 1;
34     }
35     for (int i = len; i > 1; --i)
36     {
37         string tmp = "";
38         for (int j = i; j <= len; ++j) tmp += s[j];
39         for (int j = 1; j < i; ++j) tmp += s[j];
40         if (!same(tmp) && ok(tmp)) return 1;
41     }
42     string tmp = "";
43     for (int i = 1; i <= len / 2; ++i)
44     {
45         tmp += s[i];
46         if (!ok(tmp)) 
47             return 2;
48     }
49     return -1;
50 }
51 
52 
53 int main()
54 {
55     while (scanf("%s", s + 1) != EOF)
56     {
57         int res = solve();
58         if (res != -1) printf("%d\n", res);
59         else puts("Impossible");
60     }
61     return 0;
62 }
View Code

F. Sasha and Interesting Fact from Graph Theory

Upsolved.

題意:

要求構造一棵$n$個點的樹,使得$a->b的距離為m$

$每條邊的邊權在[1, m]範圍內$

$求生成樹個數$

思路:

我們可以枚舉$a->b的邊數,那麽邊權的分配就有C_{m - 1}^{edge}$

$並且可以有順序的選出edge - 1個點是A_{n}^{edge - 1}$

$那麽再考慮其他點,剩下的點的個數為n - edge - 1$

$這個點的邊的選擇都是m種,就是m^{n - edge - 1}$

$再考慮他們構成一棵樹,就是有n個點,要分配到k個不同的連通塊構成的森林的方案$

$根據Cayley公式f(n, k) = k \cdot n^{n - y - 1}$

$我們要的就是f(n, edge +1)$

技術分享圖片
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define ll long long
 5 #define N 1000010
 6 const ll p = (ll)1e9 + 7;
 7 int n, m, a, b;
 8 ll fac[N], inv[N];
 9 
10 ll qmod(ll base, ll n)
11 {
12     ll res = 1;
13     while (n)
14     {
15         if (n & 1) res = res * base % p;
16         base = base * base % p;
17         n >>= 1;
18     }
19     return res;
20 }
21     
22 ll C(int n, int m)
23 {
24     if (m > n) return 0;
25     return fac[n] * inv[m] % p * inv[n - m] % p;
26 }
27 
28 int main()
29 {
30     fac[0] = 1;
31     for (int i = 1; i <= 1000000; ++i) fac[i] = fac[i - 1] * i % p;
32     inv[1000000] = qmod(fac[1000000], p - 2);
33     for (int i = 1000000; i >= 1; --i) inv[i - 1] = inv[i] * i % p;
34     while (scanf("%d%d%d%d", &n, &m, &a, &b) != EOF)
35     {
36         ll base = 1;
37         ll res = 0;
38         for (int i = n - 2; i >= 0; --i)
39         {
40             base = 1ll * qmod(m, n - 2 - i); 
41             if (n - i - 3 >= 0)
42                 base = base * (i + 2) % p * qmod(n, n - i - 3) % p;
43             res = (res + C(m - 1, i) * C(n - 2, i) % p * base % p * fac[i] % p) % p;
44             //base = base * m % p * (i + 1) % p; 
45         }
46         printf("%lld\n", res);
47     }
48     return 0;
49 }
View Code

Codeforces Round #539 (Div. 2)