Codeforces Round #576 (Div. 2)

A - City Day

题意:给n,x,y和数组a[n],求最小的下标d,使得有a[d-x,d-x+1,……d-1,d+1,d-1,d+1,……d+y-1,d+y]都比a[d]小,若d-x<=0则从1开始,若d+y>n,则从n为结尾。

分析:对于a[i],要在左端找到比a[i]大的且最近的数,在右端找到比a[i]大且最近的数,用单调栈。然后从1开始看到n,看到哪个符合条件就作为答案输出。

 1 #include <bits/stdc++.h>
 2 
 3 #define maxn 100005
 4 #define mod 1000000007
 5 #define inf 0x3f3f3f3f
 6 #define start ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
 7 #define ll long long
 8 #define LL long long
 9 using namespace std;
10 int a[maxn];
11 int l[maxn];
12 int r[maxn];
13 
14 int main() {
15     start;
16     int n, x, y;
17     cin >> n >> x >> y;
18     int t = 0;
19     for (int i = 1; i <= n; ++i)
20         cin >> a[i];
21     stack<int> s;
22     s.push(0);
23     for (int i = 1; i <= n; ++i) {
24         while (a[s.top()] > a[i])
25             s.pop();
26         l[i] = s.top();
27         s.push(i);
28     }
29     stack<int> tmp;
30     tmp.push(n + 1);
31     for (int i = n; i > 0; --i) {
32         while (a[tmp.top()] > a[i])
33             tmp.pop();
34         r[i] = tmp.top();
35         tmp.push(i);
36     }
37     for (int i = 1; i <= n; ++i) {
38         if ((i - l[i] - 1 >= x || l[i] == 0) && (r[i] - i - 1 >= y || r[i] == n + 1)) {
39             cout << i << endl;
40             return 0;
41         }
42     }
43     return 0;
44 }
View Code

B - Water Lily

题意:离水面高H的花,走了L触及水面,问水深。

分析:勾股定理。设答案为X,X*X+L*L=(X+H)*(X+H)。(cin和printf同用的不良风格)

 1 #include <bits/stdc++.h>
 2 
 3 #define maxn 100005
 4 #define mod 1000000007
 5 #define inf 0x3f3f3f3f
 6 #define start ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
 7 #define ll long long
 8 #define LL long long
 9 using namespace std;
10 
11 int main() {
12     start;
13     ll h, l;
14     cin >> h >> l;
15     printf("%.13lf",(l * l - h * h) * 1.0 / (2 * h));
16     return 0;
17 }
View Code

C - MP3

题意:给定n个数,假设有K个不同的数,就要使用k=ceil(log2(K)) bits去存储每个数,总共需要n*k bits,一个大小为i bytes(1 byte=8 bits)的磁盘。对于一个区间[l,r]我们可以将小于l的数变成l,将大于r的数变成r,问最少变多少数使得磁盘能存下这些数。

分析:能存i bytes,即能存8*i bits,则k=8*i/n,则K=2^(8*i/n),此即能存下的不同种类的数字(认为是l到r区间长度共有K,wa了一个小时,看到别人代码才发现),可表示为(1<<k)。

(1)排序,可先找K个不同的数,然后滑动区间,左端点将所有等于左端点的数去掉,右端点加上右方下一组相等的数。同时要找最少的变化数,即找区间内最多的数。

 1 #include <bits/stdc++.h>
 2 
 3 #define maxn 400005
 4 #define mod 1000000007
 5 #define inf 0x3f3f3f3f
 6 #define start ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
 7 #define ll long long
 8 #define LL long long
 9 using namespace std;
10 ll a[maxn];
11 
12 int main() {
13     start;
14     int n, I;
15     cin >> n >> I;
16     for (int i = 1; i <= n; ++i)
17         cin >> a[i];
18     sort(a + 1, a + n + 1);
19     int sum = 0;
20     int maxt = 0;
21     ll k = 8 * I / n;
22     if (k >= 30) {//(1<<30)>1e9
23         cout << 0 << endl;
24         return 0;
25     }
26     int K = (1 << k);
27     int l = 1, r = 1;
28     a[n + 1] = (1ll << 31);
29     a[0] = -1;//两个哨兵
30     int count = 1;
31     for (; r <= n; ++r) {
32         if (a[r] != a[r + 1]) {
33             if (count == K)
34                 break;
35             ++count;
36         }
37     }
38     if (r >= n) {//如果一整段区间都符合条件,且还可以存数,r会到n+1处
39         cout << 0 << endl;
40         return 0;
41     }
42     maxt = sum = r - l + 1;
43     for (; l + maxt - 1 <= n;) {
44         int t = l;
45         for (; t <= n; ++t)
46             if (a[t] != a[l])
47                 break;
48         if (t == n + 1)
49             break;
50         sum -= (t - l);
51         l = t;
52         ++r;
53         ++sum;
54         for (; r <= n; ++r) {
55             if (a[r + 1] != a[r])
56                 break;
57             ++sum;
58         }
59         maxt = max(maxt, sum);
60         if (r == n)
61             break;
62     }
63     cout << n - maxt << endl;
64     return 0;
65 }
View Code

(2)排序,记录每一个相同的数有多少种,记为一组,然后找K组,然后滑动区间每次保证K组,找到区间内最多的数。

 1 #include <bits/stdc++.h>
 2 
 3 #define maxn 400005
 4 #define mod 1000000007
 5 #define inf 0x3f3f3f3f
 6 #define start ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
 7 #define ll long long
 8 #define LL long long
 9 using namespace std;
10 ll a[maxn];
11 
12 int main() {
13     start;
14     int n, I;
15     cin >> n >> I;
16     for (int i = 1; i <= n; ++i)
17         cin >> a[i];
18     sort(a + 1, a + n + 1);
19     ll k = 8 * I / n;
20     if (k >= 30) {//(1<<30)>1e9
21         cout << 0 << endl;
22         return 0;
23     }
24     a[n + 1] = -1;//哨兵
25     int K = (1 << k);
26     vector<int> num;
27     int cnt = 1;
28     for (int i = 1; i <= n; ++i) {
29         if (a[i] == a[i + 1])
30             ++cnt;
31         else {
32             num.push_back(cnt);
33             cnt = 1;
34         }
35     }
36     if (num.size() < K) {
37         cout << 0 << endl;
38         return 0;
39     }
40     int sum = 0;
41     int l = 0, r = K - 1;
42     for (int i = 0; i <= r; ++i)
43         sum += num[i];
44     int maxt = sum;
45     for (; r + 1 < num.size();) {
46         sum -= num[l];
47         ++l;
48         ++r;
49         sum += num[r];
50         maxt = max(maxt, sum);
51     }
52     cout << n - maxt << endl;
53     return 0;
54 }
View Code

D - Welfare State

题意:给n个数,有两种操作,第一种操作输入p和x,将第p个数变为x;第二种操作输入x,将所有小于x的数变成x。

分析:对于a[i],最后的第一种操作一定是有效的,假设变为x,如果在该操作后出现了大于第二种操作输入的y,且y>x,则该数变成y。我们将q种操作编号为1~q。记录一个p[n]数组,一个t[n]数组,对于第i个数,p[i]表示最后的第一种操作,t[i]表示这个操作的编号。再记录一个maxi[n]数组,maxi[i]表示在第i个操作(包括第i个操作)之后的第二个操作变成的最大的数。

 1 #include <bits/stdc++.h>
 2 
 3 #define maxn 400005
 4 #define mod 1000000007
 5 #define inf 0x3f3f3f3f
 6 #define start ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
 7 #define ll long long
 8 #define LL long long
 9 using namespace std;
10 ll a[maxn];
11 ll p[maxn];
12 ll t[maxn];
13 ll maxi[maxn];
14 
15 int main() {
16     start;
17     memset(p, -1, sizeof(p));
18     int n;
19     cin >> n;
20     for (int i = 1; i <= n; ++i)
21         cin >> a[i];
22     int q;
23     cin >> q;
24     for (int i = 0; i < q; ++i) {
25         int x;
26         cin >> x;
27         if (x == 1) {
28             int y, z;
29             cin >> y >> z;
30             p[y] = z;
31             t[y] = i;
32         } else {
33             cin >> maxi[i];
34         }
35     }
36     /*后缀操作,对于第i次操作,假设是第二种操作,如果后续有比该操作更大的值,则该操作可被后续操作覆盖*/
37     /* 假设是第一种操作,假设后续有比该操作更大的第二次操作的值,同样可被覆盖*/
38     for (int i = q - 2; i >= 0; --i)
39         maxi[i] = max(maxi[i], maxi[i + 1]);
40     for (int i = 1; i <= n; ++i) {
41         int maxt = t[i];//a[i]最后进行第一次操作的编号
42         if (p[i] == -1)//如果a[i]没有进行第一次操作,t[i]为0
43             cout << max(a[i], maxi[maxt]) << ' ';//如果第0次操作后进行的第二种操作的x比a[i]大则输出x,反之亦反。
44         else if (maxi[maxt] > p[i])//a[i]在最后一次(maxt次)第一种操作变成了x,在第maxt次后有一个第二种操作,该操作的值大于x,则输出该值
45             cout << maxi[maxt] << ' ';
46         else//第maxt操作将a[i]变成了p[i]且后续无有效操作
47             cout << p[i] << ' ';
48     }
49     return 0;
50 }
View Code

E和F我这种菜鸡估计是A不出来的。

 (如有问题,请在评论区和我说)

原文地址:https://www.cnblogs.com/F-Mu/p/11278162.html