标签:比较 子序列 sign 距离 lap main event printf unsigned
未补
未补
签到题之一,排列计数。
题意:给你排列的长度$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$满足$$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 }
防爆零签到题,很简单就不说了。
经典约瑟夫环
题意:约瑟夫环模型,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 }
计算几何,完全不会,跳过
留坑
总结:本套题难度可以说比较大,并且很有oi风格,不愧是csy大佬和另外两位大佬出的题,点赞。
2018-2019 ACM-ICPC, Asia Shenyang Regional Contest(补题)
标签:比较 子序列 sign 距离 lap main event printf unsigned
原文地址:https://www.cnblogs.com/UtopioSPH001/p/10057028.html