codeforces round#509
博主水平不高, 只能打完$4$题, QAQ什么时候才能变强啊嘤嘤嘤
订正完6题了, 还想打今天下午的CF , 只能迟十分钟了, 掉分预定
A. Heist
输出 $max - min + n - 1$即可
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define rd read() 5 using namespace std; 6 7 const int N = 1e3 + 5; 8 const int inf = ~0U >> 1; 9 10 int n, a[N], x, maxn, minn = inf; 11 12 int read () { 13 int X = 0, p = 1; char c = getchar(); 14 for(; c > '9' || c < '0'; c = getchar()) if(c == '-') p = -1; 15 for(; c >= '0' && c <= '9'; c = getchar()) X = X * 10 + c - '0'; 16 return X * p; 17 } 18 19 int main() 20 { 21 n = rd; 22 for(int i = 1; i <= n; ++i) { 23 a[i] = rd; 24 minn = min(minn, a[i]); 25 maxn = max(maxn, a[i]); 26 } 27 printf("%d\n", maxn - minn - n + 1); 28 }
B. Buying a TV Set
Description
要求找出 $ i<=a, j<=b$ 并且 $ i : j = x : y$
Solution
先将$ x, y$约分, 输出$ \min(i \div x, j \div y)$ 即可
Code
1 #include<cstdio> 2 #define ll long long 3 4 ll gcd(ll x, ll y) { 5 return x % y ? gcd(y, x % y) : y; 6 } 7 8 int main() 9 { 10 ll a, b, x, y, d; 11 scanf("%I64d%I64d%I64d%I64d", &a, &b, &x, & y); 12 d = gcd(x, y); 13 x /= d; y /= d; 14 ll tmp1 = a / x, tmp2 = b / y; 15 printf("%I64d\n", tmp1 > tmp2 ? tmp2 : tmp1); 16 }
C. Coffee Break
Description
主人公想要在$n$个时间点喝咖啡, 但是老板要求他 每次 喝咖啡 的 间隔 必须 $>=d$
求问主人公至少要 几天 才能在 每个时间点 都喝过咖啡。
Solution
贪心 + 二分查找
用Set写 复杂度更严格, 但是我没想到用Set删除。
外层枚举到每一天$i$, 如果 $i$ 没有被确定在哪一天喝, 则 $++ans$, 并在第 $ans$(当前的ans) 天喝。
接下来再查找出第一个$>= \ a[i] + d + 1$的 时刻$j$, 如果$j$ 已经被确定在哪天喝, 那么$j++$, 直到$j > n $ 或 $j$ 没有被确定在哪一天喝。
把 $j$ 和 $i$ 确定为同一天喝就可以惹。
复杂度并不是严格的$O(nlogn)$, 希望不要呱
Code
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define rd read() 5 using namespace std; 6 7 const int N = 2e5 + 5; 8 9 int n, m, d, ans; 10 int b[N]; 11 12 struct node { 13 int pos, id, day; 14 }a[N]; 15 16 int read() { 17 int X = 0, p = 1; char c =getchar(); 18 for(;c > '9' || c < '0'; c = getchar()) if(c == '-') p = -1; 19 for(;c >= '0' && c <= '9'; c = getchar()) X = X * 10 + c - '0'; 20 return X * p; 21 } 22 23 int fd(int x) { 24 return lower_bound(b + 1, b + 1 + n, x) - b; 25 } 26 27 int cmp1(const node &A, const node &B) { 28 return A.pos < B.pos; 29 } 30 31 int cmp2(const node &A, const node &B) { 32 return A.id < B.id; 33 } 34 35 int main() 36 { 37 n = rd; m = rd; d = rd; 38 for(int i = 1; i <= n; ++i) 39 b[i] = a[i].pos = rd, a[i].id = i; 40 sort(b + 1, b + 1 + n); 41 sort(a + 1, a + 1 + n, cmp1); 42 for(int i = 1; i <= n; ++i) { 43 if(!a[i].day) a[i].day = ++ans; 44 int tmp = a[i].pos + d + 1; 45 tmp = fd(tmp); 46 while(a[tmp].day && tmp <= n) 47 tmp++; 48 if(tmp <= n) a[tmp].day = a[i].day; 49 } 50 printf("%d\n", ans); 51 sort(a + 1, a + 1 + n, cmp2); 52 printf("%d", a[1].day); 53 for(int i = 2; i <= n; ++i) 54 printf(" %d", a[i].day); 55 puts(""); 56 }
D. Glider
Description
求出从哪一点开始下飞机, 滑翔的水平距离最远。 在上升气流的区间内 水平飞行, 在其他地方会 $1 : 1$地 下降
并且输入的 上升气流的区间不重合、且递增。
Solution
官方题解 二分 + 前缀和。
我打出了个倍增。。。
定义$nxt[i][j]$ 为 $i$ 之后的 第 $2^j$ 个区间(这不是可以直接$O(1)$算吗??? 我怎么知道我当时怎么想的。。。
$dis[i][j]$ 为 $i$ 到 之后第 $2 ^ j$ 个区间 的空隙长度(即没有上升气流的长度)。
$sum[i] $为前 $i$ 个上升气流的总长度
由于空隙长度 必须 $ <= \ h$, 所以可以倍增求出最远到哪个区间。
然后枚举下飞机的区间, 倍增求出最远到达的区间, 前缀和查询 上升气流长度 并更新答案。
Code
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define rd read() 5 using namespace std; 6 7 const int N = 2e5 + 5; 8 const int base = 19; 9 10 int l[N], r[N], h, n, maxn = h, sum[N]; 11 int dis[N][20], nxt[N][20]; 12 13 int read() { 14 int X = 0, p = 1; char c = getchar(); 15 for(;c > '9' || c < '0'; c = getchar()) if(c == '-') p = -1; 16 for(; c >= '0' && c <= '9'; c = getchar()) X = X * 10 + c - '0'; 17 return X * p; 18 } 19 20 void cal(int now) { 21 int rest = h, tmp = now; 22 for(int k = base; ~k; --k) 23 if(nxt[tmp][k] && rest - dis[tmp][k] > 0) 24 rest -= dis[tmp][k], tmp = nxt[tmp][k]; 25 maxn = max(maxn, h + sum[tmp] - sum[now - 1]); 26 } 27 28 int main() 29 { 30 n = rd; h = rd; 31 for(int i = 1; i <= n; ++i) 32 l[i] = rd, r[i] = rd; 33 for(int i = 1; i <= n; ++i) 34 sum[i] = sum[i - 1] + r[i] - l[i]; 35 for(int i = 1; i < n; ++i) { 36 dis[i][0] = l[i + 1] - r[i]; 37 nxt[i][0] = i + 1; 38 } 39 for(int k = 1; k <= base; ++k) 40 for(int i = 1; i <= n; ++i) { 41 nxt[i][k] = nxt[nxt[i][k - 1]][k - 1]; 42 dis[i][k] = dis[i][k - 1] + dis[nxt[i][k - 1]][k - 1]; 43 } 44 for(int i = 1; i <= n; ++i) cal(i); 45 printf("%d\n", maxn); 46 }
之后的就不会噜
upd
订正了一波。
E. Tree Reconstruction
Solution
显然, 输入中的 $b$ 肯定等于$N$, 否则就一定不存在这样的一棵树。
对于每个节点 $i$ $(i < n)$ , 它在输入中出现的次数为 $cnt[i]$, 那么 对于每个 $k$ , $cnt[1] \ + cnt[2] \ ... \ + cnt[k] \ <= k$ , 否则就不存在。
然后就构造一条链, 一端是$N$, 另一端通过算法来补全。
依次枚举$i$, 如果$cnt[i] \ == \ 0$, 那么把它继续留在$Set$里面, 到之后用。
如果$cnt[i] \ > \ 0$, 那么 把 $i$ 添到链中, 因为在 $i$ 之前添入链中的节点编号都 $ < \ i$, 也就是对 $i$ 不产生贡献。
接着往 链中添入 $cnt[i] \ - \ 1$ 个节点(这些节点的编号可以保证都 $< \ i$) 。
枚举结束后再将 $N$ 与最后一个添入的节点连边
Code
1 #include<cstdio> 2 #include<cstring> 3 #include<set> 4 #define rd read() 5 using namespace std; 6 7 const int N = 1e5 + 5; 8 9 int cnt[N], n; 10 11 set<int>st; 12 13 int read() { 14 int X = 0, p = 1; char c = getchar(); 15 for(;c > '9' || c < '0'; c = getchar()) if(c == '-') p = -1; 16 for(;c >= '0' && c <= '9'; c = getchar()) X = X * 10 + c - '0'; 17 return X * p; 18 } 19 20 int main() 21 { 22 n = rd; 23 for(int i = 1; i < n; ++i) { 24 int u = rd, v = rd; 25 if(v != n) return puts("NO"), 0; 26 cnt[u]++; 27 } 28 int cur = 0; 29 for(int i = 1; i < n; ++i) 30 if((cur += cnt[i]) > i) 31 return puts("NO"), 0; 32 for(int i = 1; i < n; ++i) 33 st.insert(i); 34 puts("YES"); 35 int last = 0; 36 for(int i = 1; i < n; ++i) { 37 if(cnt[i]) { 38 st.erase(i); 39 if(last) 40 printf("%d %d\n", last, i); 41 cnt[i]--; 42 last = i; 43 } 44 while(cnt[i]) { 45 printf("%d %d\n", last, *st.begin()); 46 last = *st.begin(); 47 cnt[i]--; 48 st.erase(*st.begin()); 49 } 50 } 51 printf("%d %d\n", last, n); 52 }
F. Ray in the tube
感觉题解写的非常靠谱|清楚 , 题解传送门
Solution
设$A, B$ 两点的水平距离为 $d$
要使传感器感应到同一条光, 那么就要满足
在第一条线上 : $a_i \ = \ a_j (mod \ 2d)$
在第二条线上: $b_i \ = \ b_j = a_k \ + \ d \ (mod \ 2d)$( $a$ 表示第一条线上的点, $b$ 表示第二条线上的点)
有一个神奇的结论: 要使其方案最优, 必定有$d \ = \ 2^i$ $(i \ >= \ 0$)。
反证 : 假如 $ d \ = \ k \ * \ 2^i$ ($k$ 为奇数), 那么它到达的点, $2^i$ 同样也能到达, 并且$2^i$ 所能到达的点更多。
然后我们就枚举$d$ ($log1e9$种可能), 用 $MAP$ 记录 $a_i \ mod \ 2d$, 和 $(b_i \ + d) \ mod \ 2d$, 并在记录中更新答案。
总复杂度 $O(NlogNlog1e9)$
Code
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<map> 5 #define rd read() 6 using namespace std; 7 8 const int N = 1e5 + 15; 9 10 map<int, int> M; 11 12 int a[N], b[N], n, m, maxn = 2; 13 14 int read() { 15 int X = 0, p = 1; char c = getchar(); 16 for(; c > '9' || c < '0'; c = getchar()) if(c == '-') p = -1; 17 for(; c >= '0' && c <= '9'; c = getchar()) X = X * 10 + c - '0'; 18 return X * p; 19 } 20 21 int main() 22 { 23 n = rd; rd; 24 for(int i = 1; i <= n; ++i) 25 a[i] = rd; 26 m = rd; rd; 27 for(int i = 1; i <= m; ++i) 28 b[i] = rd; 29 for(int tmp = 1; tmp <= 1e9; tmp <<= 1) { 30 M.clear(); 31 for(int i = 1; i <= n; ++i) { 32 int k = a[i] % (tmp << 1); 33 if(!M.count(k)) M[k] = 1; 34 else {maxn = max(maxn, ++M[k]);} 35 } 36 for(int i = 1; i <= m; ++i) { 37 int k = (1LL * b[i] + tmp) % (tmp << 1); 38 if(!M.count(k)) M[k] = 1; 39 else {maxn = max(maxn, ++M[k]);} 40 } 41 } 42 printf("%d\n", maxn); 43 }