cychester

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 }
Heist

 


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 }
Buying a TV set

 

 

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 }
Coffee Break

 

 

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 }
Glider

 

 

之后的就不会噜

 

 


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 }
Tree Reconstruction

 

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 }
Ray in the tube

 

posted on 2018-09-16 21:18  cychester  阅读(195)  评论(0编辑  收藏  举报

导航