Hello2020(前四题题解)
Hello,2020!新的一年从快乐的掉分开始……
我在m3.codeforces.com这个镜像网站中一开始还打不开D题,我……
还有话说今天这场为什么那么多二分。
比赛传送门:https://codeforces.com/contest/1284。
A. New Year and Naming
题目大意:这题就是一个干支纪年法。每年的名字分两段,第一段在n个字符串中取,第二段在m个字符串中取,每过一年就各取下一个,如果取到n(m)就去取第一个。
纯模拟,加上一点点字符串操作。
又丑又长的代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <vector> 6 #define rep(x, l, r) for(int x = l; x <= r; x++) 7 #define repd(x, r, l) for(int x = r; x >= l; x--) 8 #define clr(x, y) memset(x, y, sizeof(x)) 9 #define all(x) x.begin(), x.end() 10 #define pb push_back 11 #define mp make_pair 12 #define MAXN 2005 13 #define fi first 14 #define se second 15 #define SZ(x) ((int)x.size()) 16 using namespace std; 17 typedef long long ll; 18 typedef vector<int> vi; 19 typedef pair<int, int> pii; 20 const int INF = 1 << 30; 21 const int p = 1000000009; 22 int lowbit(int x){ return x & (-x);} 23 int fast_power(int a, int b){ int x; for(x = 1; b; b >>= 1){ if(b & 1) x = 1ll * x * a % p; a = 1ll * a * a % p;} return x % p;} 24 25 char st1[MAXN][25], st2[MAXN][25]; 26 27 int main(){ 28 int n, m; 29 scanf("%d%d", &n, &m); 30 rep(i, 1, n) scanf("%s", st1[i]); 31 rep(i, 1, m) scanf("%s", st2[i]); 32 int q; 33 scanf("%d", &q); 34 rep(i, 1, q){ 35 int x; 36 scanf("%d", &x); 37 int len = strlen(st1[(x - 1) % n + 1]); 38 rep(j, 0, len - 1) putchar(st1[(x - 1) % n + 1][j]); 39 puts(st2[(x - 1) % m + 1]); 40 } 41 return 0; 42 }
B.New Year and Ascent Sequence
题目大意:给你n个序列,每次取任意两个序列(可以取同一个,并且交换前后顺序算不同种)接起来(比如说‘11’和‘22’就是‘1122’)。问这n2个接成序列中共有多少个序列中存在顺序对。
不难看出,如果一个序列中本身存在顺序对,接成的序列也肯定存在顺序对。
判断方法
if(x > minx) flag = 1;
将它们找出来后直接统计入答案,套上一个小学学的容斥原理
ans = 1ll * 2 * cnt1 * n - 1ll * cnt1 * cnt1;
然后主要问题就是这些剩下的没有顺序对的序列。
很显然凡是最大值比这个序列最小值大的,就可以和这个序列接起来。
将最大值排序后二分一下最小的最大值就好。
代码如下
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <vector> 6 #define rep(x, l, r) for(int x = l; x <= r; x++) 7 #define repd(x, r, l) for(int x = r; x >= l; x--) 8 #define clr(x, y) memset(x, y, sizeof(x)) 9 #define all(x) x.begin(), x.end() 10 #define pb push_back 11 #define mp make_pair 12 #define MAXN 100005 13 #define fi first 14 #define se second 15 #define SZ(x) ((int)x.size()) 16 using namespace std; 17 typedef long long ll; 18 typedef vector<int> vi; 19 typedef pair<int, int> pii; 20 const int INF = 1 << 30; 21 const int p = 1000000009; 22 int lowbit(int x){ return x & (-x);} 23 int fast_power(int a, int b){ int x; for(x = 1; b; b >>= 1){ if(b & 1) x = 1ll * x * a % p; a = 1ll * a * a % p;} return x % p;} 24 25 vi a, b; 26 27 int main(){ 28 int n; 29 scanf("%d", &n); 30 int cnt1 = 0, cnt2 = 0; 31 rep(i, 1, n){ 32 int k; 33 scanf("%d", &k); 34 int minx = INF, maxx = -INF; 35 bool flag = 0; 36 rep(j, 1, k){ 37 int x; 38 scanf("%d", &x); 39 if(x > minx) flag = 1; 40 minx = min(minx, x); 41 maxx = max(maxx, x); 42 } 43 if(flag) cnt1++; 44 else{ 45 cnt2++; 46 a.pb(minx); 47 b.pb(maxx); 48 } 49 } 50 sort(all(b)); 51 ll ans = 1ll * 2 * cnt1 * n - 1ll * cnt1 * cnt1; 52 rep(i, 0, SZ(b) - 1){ 53 ans += cnt2 - (upper_bound(all(b), a[i]) - b.begin()); 54 } 55 printf("%I64d ", ans); 56 return 0; 57 }
C.New Year and Permutation
题目大意:在所有由[1,n]组成的排列中,有多少对数(l,r)满足max{pl,pl+1,…,pr} - min{pl,pl+1,…,pr} = r - l。
似乎解释的不是很清楚,再来个样例解释一下。
当n = 3时,所有的排列为[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]。
对于[1,2,3]:(1,1)中max = 1, min = 1, r - l = 0,成立;(1,3)中max = 3, min = 1, r - l = 2,成立。
对于[1,3,2]:(1,2)中max = 3, min = 1, r - l = 1,不成立。
别的懒得说了,原题样例说明有。
这道题一开始看的时候有点慌,浪费了好多时间。
后来一想,不就分别统计长度为i的子段满足条件。
我们可以很轻松的求出不同子段出现次数,所有该长度的子段出现次数为:
排列个数×每个排列中出现的次数 = n!×(n - i +1)
然后该长度不同子段的个数为n!/ (n - i)!,稍微证明一下或者列举几个便可以得出。
然后求所有符合条件的字段个数,(1,2,…,i ) 到(n - i + 1,n - i + 2,…, n )一共有n - i + 1种,然后每种的排列有i!个。
所有长度为i的字段对答案的贡献 = 不同子段的出现个数 × 符合的长度为i子段的个数
= n!× (n - i + 1) / ( n!/ ( n - i )!) × ( n - i + 1 ) × i!
= ( n - i )! × ( n - i + 1) × ( n - i +1 ) × i!
这个式子看上去挺好看的,然后求个总和就好。
代码特别短:
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <vector> 6 #define rep(x, l, r) for(int x = l; x <= r; x++) 7 #define repd(x, r, l) for(int x = r; x >= l; x--) 8 #define clr(x, y) memset(x, y, sizeof(x)) 9 #define all(x) x.begin(), x.end() 10 #define pb push_back 11 #define mp make_pair 12 #define MAXN 250005 13 #define fi first 14 #define se second 15 #define SZ(x) ((int)x.size()) 16 using namespace std; 17 typedef long long ll; 18 typedef vector<int> vi; 19 typedef pair<int, int> pii; 20 const int INF = 1 << 30; 21 int p; 22 int lowbit(int x){ return x & (-x);} 23 int fast_power(int a, int b){ int x; for(x = 1; b; b >>= 1){ if(b & 1) x = 1ll * x * a % p; a = 1ll * a * a % p;} return x % p;} 24 25 int pow[MAXN]; 26 27 int main(){ 28 int n; 29 scanf("%d%d", &n, &p); 30 pow[0] = 1; 31 rep(i, 1, n){ 32 pow[i] = 1ll * pow[i - 1] * i % p; 33 } 34 int ans = 0; 35 rep(i, 1, n){ 36 int s = 1ll * pow[n - i] * (n - i + 1) % p * (n - i + 1) % p * pow[i] % p; 37 ans = (ans + s) % p; 38 } 39 printf("%d ", ans); 40 return 0; 41 }
D.New Year and Conference
题目大意:有n个人,每个人在a会场讲话开始时间为sai,结束时间为eai,在b会场开始时间为sbi,结束时间为ebi。是否存在一个集合中的人在a市场没有时间重叠在b市场有重叠或在b市场没有重叠在a市场有有重叠。设两个人开始结束时间分别为(u,v)和(x,y),当max(x,u) <= min(y,v)时两人重叠。存在重叠时输出“NO”,否则输出“YES”(似乎有什么不对的地方)。
提前申明一下,这道题我自己代码一直过不了,但是群里有人按照我的解法过了……代码也差不多……
只WA了第10个点(加了个特判过了),现在对拍跑了2个半小时还没跑出一组错误数据……
我的解法甚是奇怪……
首先判断a会场不重叠b会场重叠的情况,发现我们对于每个人a会场只要判断左边不重叠的情况,右边的到时候会枚举到的。
对于i这个人,要是eaj < sai,那么这两个人就不会重叠。
所以我们以sai为关键字进行排序,二分查找可以找出所有与i不重叠的人。
但是对每个人找他左边的人的区间肯定要超时,因为左边的人一定是从1开始的一个区间,我们记录下对于每个人i所有的以i为最右边的不重叠的人pi,j。(即不存在一个人k使得eai < eak < sapi,j)
然后只需要判断b会场是否有重叠,也就是说对第i个人,所有他左边的不重叠人j的[sbj,ebj]这个区间是否和[sbi,ebi]有重合,变成了一个区间覆盖问题。
用线段树进行维护,将区间[sbi,ebi]更改为已覆盖,判断pi中是否有点的讲话区间中有已覆盖的点。
对于另一种情况b会场不重叠a会场重叠情况和这个相同。
放上我的WA掉的代码(仅供参考,对着打出锅了别怪我):
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <vector> 6 #define rep(x, l, r) for(int x = l; x <= r; x++) 7 #define repd(x, r, l) for(int x = r; x >= l; x--) 8 #define clr(x, y) memset(x, y, sizeof(x)) 9 #define all(x) x.begin(), x.end() 10 #define pb push_back 11 #define mp make_pair 12 #define MAXN 500005 13 #define MAXM 2000005 14 #define fi first 15 #define se second 16 #define SZ(x) ((int)x.size()) 17 using namespace std; 18 typedef long long ll; 19 typedef vector<int> vi; 20 typedef pair<int, int> pii; 21 const int INF = 1 << 30; 22 const int p = 1000000009; 23 int lowbit(int x){ return x & (-x);} 24 int fast_power(int a, int b){ int x; for(x = 1; b; b >>= 1){ if(b & 1) x = 1ll * x * a % p; a = 1ll * a * a % p;} return x % p;} 25 26 struct node1{ 27 int l1, r1, l2, r2; 28 }a[MAXN]; 29 struct node2{ 30 int l, r; 31 bool flag, tag; 32 }tree[MAXM]; 33 bool ans; 34 int num[MAXM]; 35 vi ve1[MAXN], ve2[MAXN]; 36 37 void pushup(int q){ 38 tree[q].flag = tree[q << 1].flag || tree[q << 1 | 1].flag; 39 } 40 41 void pushdown(int q){ 42 if(!tree[q].tag) return; 43 tree[q << 1].flag = tree[q << 1].tag = 1; 44 tree[q << 1 | 1].flag = tree[q << 1 | 1].tag = 1; 45 tree[q].tag = 0; 46 } 47 48 void build(int q, int l, int r){ 49 tree[q].l = l; 50 tree[q].r = r; 51 tree[q].tag = 0; 52 tree[q].flag = 0; 53 if(l == r) return; 54 int mid = (l + r) >> 1; 55 build(q << 1, l, mid); 56 build(q << 1 | 1, mid + 1, r); 57 pushup(q); 58 } 59 60 void update(int q, int l, int r){ 61 if(tree[q].l > r || tree[q].r < l) return; 62 if(tree[q].l >= l && tree[q].r <= r){ 63 tree[q].flag = 1; 64 tree[q].tag = 1; 65 return; 66 } 67 pushdown(q); 68 update(q << 1, l, r); 69 update(q << 1 | 1, l, r); 70 pushup(q); 71 } 72 73 void query(int q, int l, int r){ 74 if(tree[q].l > r || tree[q].r < l) return; 75 if(tree[q].l >= l && tree[q].r <= r){ 76 ans = ans || tree[q].flag; 77 return; 78 } 79 pushdown(q); 80 query(q << 1, l, r); 81 query(q << 1 | 1, l, r); 82 pushup(q); 83 } 84 85 bool cmp1(node1 a, node1 b){ 86 return a.r1 < b.r1; 87 } 88 89 bool cmp2(node1 a, node1 b){ 90 return a.r2 < b.r2; 91 } 92 93 int main(){ 94 int n, m = 0; 95 scanf("%d", &n); 96 rep(i, 1, n){ 97 scanf("%d%d%d%d", &a[i].l1, &a[i].r1, &a[i].l2, &a[i].r2); 98 num[++m] = a[i].l1; 99 num[++m] = a[i].r1; 100 num[++m] = a[i].l2; 101 num[++m] = a[i].r2; 102 } 103 sort(num + 1, num + m + 1); 104 rep(i, 1, n){ 105 a[i].l1 = lower_bound(num + 1, num + m + 1, a[i].l1) - num; 106 a[i].r1 = lower_bound(num + 1, num + m + 1, a[i].r1) - num; 107 a[i].l2 = lower_bound(num + 1, num + m + 1, a[i].l2) - num; 108 a[i].r2 = lower_bound(num + 1, num + m + 1, a[i].r2) - num; 109 } 110 sort(a + 1, a + n + 1, cmp1); 111 rep(i, 1, n){ 112 int l = 1, r = n, ans = 0; 113 while(l <= r){ 114 int mid = (l + r) >> 1; 115 if(a[mid].r1 < a[i].l1){ 116 ans = mid; 117 l = mid + 1; 118 } 119 else r = mid - 1; 120 } 121 ve1[ans].pb(i); 122 } 123 build(1, 1, m); 124 rep(i, 1, n){ 125 update(1, a[i].l2, a[i].r2); 126 rep(j, 0, SZ(ve1[i]) - 1){ 127 int x = ve1[i][j]; 128 ans = 0; 129 query(1, a[x].l2, a[x].r2); 130 if(ans){ 131 puts("NO"); 132 return 0; 133 } 134 } 135 } 136 sort(a + 1, a + n + 1, cmp2); 137 rep(i, 1, n){ 138 int l = 1, r = n, ans = 0; 139 while(l <= r){ 140 int mid = (l + r) >> 1; 141 if(a[mid].r2 < a[i].l2){ 142 ans = mid; 143 l = mid + 1; 144 } 145 r = mid - 1; 146 } 147 ve2[ans].pb(i); 148 } 149 build(1, 1, m); 150 rep(i, 1, n){ 151 update(1, a[i].l1, a[i].r1); 152 rep(j, 0, SZ(ve2[i]) - 1){ 153 int x = ve2[i][j]; 154 ans = 0; 155 query(1, a[x].l1, a[x].r1); 156 if(ans){ 157 puts("NO"); 158 return 0; 159 } 160 } 161 } 162 puts("YES"); 163 return 0; 164 }