A. Alexey and Train 链接:https://codeforces.com/problemset/problem/1501/A
题目大意 有一列火车,要从站台1开往站台n,现在给你预期到达时间$a_i$和预期发车时间$b_i$,以及列车在从i-1站驶向i站时的延误时间$tm_i$,求火车到达站台n的时间。
当延误时,列车在站台i停靠的时长T应满足:
$T\geq \lceil\frac {b_i - a_i} 2\rceil$
使实际发车时间$\geq$预期发车时间
分析 简单模拟,计算出到达每一站的时间和从每一站出发的时间即可。
AC代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <bits/stdc++.h> using namespace std ;const int N = 100 + 10 ;int a[N], b[N], t[N];int aa[N], bb[N];int n;int main () { int T; cin >> T; while (T--) { memset (aa, 0 , sizeof aa); memset (bb, 0 , sizeof bb); cin >> n; for (int i = 1 ; i <= n; i++) scanf ("%d%d" , a + i, b + i); for (int i = 1 ; i <= n; i++) scanf ("%d" , t + i); for (int i = 1 ; i <= n; i++) { aa[i] = a[i] - b[i - 1 ] + t[i] + bb[i - 1 ]; bb[i] = max(aa[i] + (int )ceil ((b[i] - a[i] + 0.0 ) / 2 ), b[i]); } cout << aa[n] << endl ; } }
B. Napoleon Cake 链接:https://codeforces.com/problemset/problem/1501/B
题目大意 一个长度为n数组,初始值都是0,有n次操作,操作i给定$a_i$,让你给区间$[i-a_i+1,i]$都加上1,最后问你哪些位大于0,哪些位等于0。
分析 因为可以很显然的转化为区间维护问题,没多想就直接上树状数组了,就ac了(幸好没卡$n\log n$)。
但是,fzh大佬指出,差分前缀和可以在$o(n)$的复杂度内解决问题,是我菜了
AC代码(树状数组) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 #include <bits/stdc++.h> using namespace std ;const int N = 2e5 + 10 ;typedef long long ll;ll n, a[N], t[N << 2 ]; void init () { memset (t, 0 , sizeof (int ) * (n << 2 )); } int lowb (int x) { return x & (-x); } void update (int x, ll k) { for (; x <= n; x += lowb(x)) t[x] += k; } int query (int x) { ll res = 0 ; for (; x > 0 ; x -= lowb(x)) res += t[x]; return res; } void modlify (int l, int r) { if (l > r) return ; l = max(l, 1 ); update(l, 1 ); update(r + 1 , -1 ); } int main () { int T; cin >> T; while (T--) { scanf ("%d" , &n); for (int i = 1 ; i <= n; i++) scanf ("%d" , a + i); init(); for (int i = n; i > 0 ; i--) { if (a[i] > 0 ) modlify(i - a[i] + 1 , i); } for (int i = 1 ; i <= n; i++) { if (query(i) > 0 ) printf ("1 " ); else printf ("0 " ); } puts ("" ); } }
C. Going Home 链接:https://codeforces.com/problemset/problem/1501/C
题目大意 给定n个数($n\leq 2e5$)$a_1,a_2……a_n$($a_i\leq2.5e6$),找出四个不同 的整数x,y,z,w,使得$a_x+a_y=a_z+a_w$。
分析 看到题目你是不是想到了meeting in the middle?如果是,那么你答对了$\sqrt{max(n)}$。
如果只看n的范围,不难猜测,我们需要在$O(n\log n)$的时间内解决这个问题,显然这几乎是不可能(是我能解决)的。但是$a_i$的值域给了一个非常奇怪的数2.5e6,这让我们有了操作空间。
首先,如果同一个数出现超过三次,那么可以很显然的得到答案,所以,我们考虑所有数出现的次数都小于等于3的情况。
此时,就算序列a中的每一个数都出现了3次,我们依然有超过5e4个不同的数 。
我们先把序列a从小到大排列,再把重复的数去掉,得到新的序列$A_1,A_2……A_m$。再对序列A做差分,得到序列$b1,b2……bm-1$,其中$b_i=a_{i+1}-a_i$。
此时,我们可以得到结论:$若i-j\geq 2 \ 且\ b_i=b_j $,那么i+1,j,i,j+1就是所求解。
那么我们假设出题者非常恶毒,他想使所有的$b_i$都尽量不相等!那么在最严苛的条件下,就有:
这时就恰好无解了(很烦)。
我们在这个条件下我们对序列b求和:
$又\because \ \ \ \ \ \sum b_i=max\{a_i\}-min\{a_i\}=2.5e6=A_m-A_1$(因为是差分)
$\therefore\ \ \ A_m-A_1=\frac {n^2} 4$
如果此时 ,我们将某个$b_i(i>2)$减少1,那么就变成了:
$\therefore\ \ \ A_m-A_1=\frac {n^2} 4-1<\frac {n^2} 4$
注意,序列b是对序列A差分得到,因此b的和永远是$A_m-A_1(等式左边)$,但是,$\frac {n^2} 4$是由等差数列求和算的。当$b_i$发生变化时,序列b就不再是等差数列,因此求和也不可以再直接由等差数列求和得到(但是可以通过补全为等差数列求和得到)。
不难发现某个$b_i(i>2)$减少1后,就必然会出现元素相同的情况,此时满足$i-j\geq 2 \ 且\ b_i=b_j $,因此一定有解。
同理,如果继续减小$b_i(i>2)$,也必然会有解的,
因此,当$\therefore\ \ \ A_m-A_1<\frac {n^2} 4$时,我们一定能找到解。
由于,$A_m-A_1<2.5e6$,所以只要$n>1000\sqrt 10\approx3162.27$,就必然有解,且必然有一组解是在序列A中两对不相交的相邻的两个数。
如果不满足这个条件,由于数据很小,暴力就好了 ,芜湖!
另外如果你足够有耐心,也可以精确算出必然有解的条件(注意上述过程只是估算,实际上n的取值最好大于3200)。
AC代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 #include <bits/stdc++.h> using namespace std ;const int N = 2e5 + 10 ;typedef long long ll;struct node { int val, x, y; node(int v, int xx, int yy) : val(v), x(xx), y(yy) {} bool operator <(const node &rhs) const { return val < rhs.val; } }; int a[N], b[N], n;int main () { cin >> n; for (int i = 0 ; i < n; i++) { scanf ("%d" , a + i); b[i] = a[i]; } set <node> s; if (n > 3e3 ) { int ans[4 ]; sort(a, a + n); node t (0 , 0 , 0 ) ; for (int i = 1 ; i < n; i++) { if (i > 1 && s.count(node(a[i] - a[i - 1 ], 0 , 0 ))) { auto x = s.find(node(a[i] - a[i - 1 ], 0 , 0 )); printf ("YES\n" ); ans[0 ] = x->x; ans[1 ] = i - 1 ; ans[2 ] = x->y; ans[3 ] = i; break ; } if (i > 1 ) s.insert(t); t = node(a[i] - a[i - 1 ], i, i - 1 ); } for (int k = 0 ; k < 4 ; k++) { int i = ans[k]; for (int j = 0 ; j < n; j++) if (a[i] == b[j]) { int ok = 1 ; for (int kk = 0 ; kk < k; kk++) if (ans[kk] == j) { ok = 0 ; break ; } if (ok) ans[k] = j; } } for (int an : ans) printf ("%d " , an + 1 ); puts ("" ); } else { for (int i = 0 ; i < n; i++) for (int j = 0 ; j < i; j++) if (i != j && !s.count(node(a[i] + a[j], 0 , 0 ))) s.insert(node(a[i] + a[j], i, j)); for (int i = 0 ; i < n; i++) for (int j = 0 ; j < i; j++) if (i != j) { if (s.count(node(a[i] + a[j], 0 , 0 ))) { auto p = s.find(node(a[i] + a[j], 0 , 0 )); if (p->x != i && p->y != j && p->x != j && p->y != i) { printf ("YES\n" ); printf ("%d %d %d %d\n" , i + 1 , j + 1 , p->x + 1 , p->y + 1 ); return 0 ; } } } printf ("NO\n" ); } }