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 }
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 }
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 }
L題 - Machining Disc Rotors
計算幾何,完全不會,跳過
M題 - Renaissance Past in Nancy
留坑
總結:本套題難度可以說比較大,並且很有oi風格,不愧是csy大佬和另外兩位大佬出的題,點贊。
