2018-2019 ACM-ICPC, Asia Shenyang Regional Contest(补题)

A题 - Sockpuppets

未补

 

B题 - Sequences Generator

未补

 

C题 - Insertion Sort

签到题之一,排列计数。

题意:给你排列的长度$n$,要求你求出排列的个数,满足对其前k项排序后其最长上升子序列至少为$n-1$。

解决:当最长上升子序列为$n$时答案明显时$k!$,为$n-1$时,相当于将$n$长的有序序列中某一个位置的数插到另一个位置去,但因为会对前$k$个排序,所以在挪动时要保证前$k$个有序即可。接下来你可以暴力求出这个值,也可以手推,这个答案为

$$k!*(k*(n-k)+(n-k-1)^{2}+n-k)$$

代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long ll;
 5 
 6 const int N = 50 + 5;
 7 
 8 ll fac[N];
 9 
10 int main()
11 {
12   int T, kase = 1;
13   ios::sync_with_stdio(false);
14   cin >> T;
15   while(T --) {
16     ll n, k, p;
17     cin >> n >> k >> p;
18     cout << "Case #" << kase ++ << ": ";
19     fac[0] = 1;
20     for(int i = 1; i <= 50; ++ i)
21       fac[i] = fac[i - 1] * i % p;
22     if(n <= k) cout << fac[n] << endl;
23     else cout << fac[k] * (k * (n - k) % p + (n - k - 1) * (n - k) % p + 1) % p << endl;
24   }
25   return 0;
26 }
View Code

 

D题 - Diameter of a Tree

留坑

 

E题 - The Kouga Ninja Scrolls

 貌似把哈密顿距离转换成切比雪夫距离,然后再用线段树维护即可,原谅我现在还不太会线段树。

 

F题 - Counting Sheep in Ami Dongsuo

留坑

 

G题 - Best ACMer Solves the Hardest Problem

假的数据结构,暴力莽过,队友已过。

 

H题 - Rainbow Graph

留坑

 

I题 - Distance Between Sweethearts

题意:给你一个函数计算六元组的权值,要求你求出所有给定范围内六元组权值和。

解决:我们考虑每个距离对答案做出的贡献,对于一个距离$d$满足$$d = M \oplus I_{b} \oplus A_{b} \oplus G_{b}\oplus I_{g} \oplus A_{g} \oplus G_{g}$$,其中M为$Ib$和$Ig$,$Ab$和$Ag$还有$Gb$和$Gg$差值的最大值。我们设这三个插值分别为$di$, $da$和$dg$,这里我们假设男生属性值都低于女生,那么上面的公式可转换成

$$d = \max\{di, da, dg\} \oplus I_{b} \oplus A_{b} \oplus G_{b} \oplus (I_{b}+di) \oplus (A_{b}+da) \oplus (G_{b}+dg) $$

 现在我们可以枚举$di$, $da$和$dg$的最大值$k$,如果三个数最大值为$k$,那么它们最大差值也不会超过$k$。所以我们在枚举到某个$k$值时预处理出所有插值为$k$且异或值为$t$的数对有多少个存到数组中,注意记住保留这个值,这样我们计算到$k$时就说明把1~k的所有差值都加在了这个数组中。

至此,我们知道了每个属性差值最大为$k$时每个异或值有多少种可能,我们把它们存到了三个数组中cnt1[a], cnt2[a], cnt3[a]。那么如果$d = k \oplus ai \oplus aa \oplus ag$,其中k为三个值差值的最大值,那么它对答案的贡献为$$d * cnt1[ai] * cnt2[aa] * cnt3[ag]$$。由容斥,我们再减掉贡献为k-1及以下的贡献即可。在计算时我们需要用卷积加速防止超时。

具体细节我们可以看代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 2048 + 5;
 5 
 6 typedef long long ll;
 7 typedef unsigned long long llu;
 8 
 9 void FWT(ll a[], int n) {
10   for(int d = 1; d < n; d <<= 1) {
11     for(int m = d << 1, i = 0; i < n; i += m) {
12       for(int j = 0; j < d; ++ j) {
13         ll x = a[i + j], y = a[i + j + d];
14         a[i + j] = x + y;
15         a[i + j + d] = x - y;
16       }
17     }
18   }
19 }
20 
21 void UFWT(ll a[], int n) {
22   for(int d = 1; d < n; d <<= 1) {
23     for(int m = d << 1, i = 0; i < n; i += m) {
24       for(int j = 0; j < d; ++ j) {
25         ll x = a[i + j], y = a[i + j + d];
26         a[i + j] = (x + y) / 2;
27         a[i + j + d] = (x - y) / 2;
28       }
29     }
30   }
31 }
32 
33 ll a[3][N], cnt[3][N];
34 ll pre[N];
35 
36 void update(int n, int m, int d, int t) {
37   for(int i = 0; i <= n && i + d <= m; ++ i)
38     cnt[t][i ^ (i + d)] ++;
39   if(d) {
40     for(int i = 0; i <= m && i + d <= n; ++ i)
41       cnt[t][i ^ (i + d)] ++;
42   }
43 }
44 
45 int main() {
46     int T, kase = 1;
47   int ib, ab, gb, ig, ag, gg;
48   scanf("%d", &T);
49   while(T --) {
50     memset(pre, 0, sizeof(pre));
51     memset(a, 0, sizeof(a));
52     memset(cnt, 0, sizeof(cnt));
53     scanf("%d%d%d%d%d%d", &ib, &ab, &gb, &ig, &ag, &gg);
54     int maxs = max({ib, ab, gb, ig, ag, gg});
55     int tmp = maxs;
56     int bl = 1;
57     llu ans = 0;
58     while(tmp) {
59       tmp >>= 1; bl <<= 1;
60     }
61     for(int d = 0; d <= maxs; ++ d) {
62       update(ib, ig, d, 0);
63       update(ab, ag, d, 1);
64       update(gb, gg, d, 2);
65       for(int i = 0; i < bl; ++ i) {
66         a[0][i] = cnt[0][i];
67         a[1][i] = cnt[1][i];
68         a[2][i] = cnt[2][i];
69       }
70       FWT(a[0], bl);
71       FWT(a[1], bl);
72       FWT(a[2], bl);
73       for(int i = 0; i < bl; ++ i) {
74         a[0][i] = a[0][i] * a[1][i] * a[2][i];
75       }
76       UFWT(a[0], bl);
77       for(int i = 0; i < bl; ++ i) {
78         ll k = 1ll * (d ^ i);
79         ans += 1ull * (a[0][i] - pre[i]) * k;
80         pre[i] = a[0][i];
81       }
82     }
83     cout << "Case #" << kase ++ << ": " << ans << endl;
84   }
85   return 0;
86 }
View Code

 

J题 - How Much Memory Your Code Is Using?

防爆零签到题,很简单就不说了。

 

K题 - Let the Flames Begin

经典约瑟夫环

题意:约瑟夫环模型,n个人,报数为k,第m个走,坐标是啥。

解决:直接上公式$$f(n, m) = (f(n-1, m-1) + k) \% n$$,那么如果m很小,我们就直接暴力,如果k很小,我们就分块处理,老实说这个题不应该现场赛过的人这么少。

代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 
 5 int main()
 6 {
 7   int T, kase = 1;
 8   scanf("%d", &T);
 9   while(T --) {
10     ll n, m, k;
11     scanf("%I64d%I64d%I64d", &n, &m, &k);
12     printf("Case #%d: ", kase ++);
13     if(m < k) {
14       ll f1 = (k-1)%(n-m+1);
15       for(ll i = n-m+2; i <= n; ++ i) {
16         f1 = (f1 + k) % i;
17       }
18       printf("%I64d\n", f1 + 1);
19     } else {
20       if(k == 1) {
21         printf("%I64d\n", m);
22         continue;
23       }
24       ll f1 = (k-1)%(n-m+1);
25       for(ll i = n-m+2, j = i; i <= n; i = j+1) {
26         ll sp = (i-1-f1)/(k-1);
27         if((i-1-f1)%(k-1)!=0) sp++;
28         if(i+sp-1>=n) {
29           f1=(f1+(n-i+1)*k)%n; break;
30         }
31         f1 = (f1+sp*k)%(i+sp-1);
32         j = i+sp-1;
33       }
34       printf("%I64d\n", f1 + 1);
35     }
36   }
37   return 0;
38 }
View Code

 

L题 - Machining Disc Rotors

计算几何,完全不会,跳过

 

M题 - Renaissance Past in Nancy

留坑

 

总结:本套题难度可以说比较大,并且很有oi风格,不愧是csy大佬和另外两位大佬出的题,点赞。

posted @ 2018-12-03 11:43  UtopioSPH  阅读(1048)  评论(2编辑  收藏  举报