A. Find The Array
题意
要你构造一个长度为$n$的数组,每个元素$a_i$满足:
- $a_i=1$
- $a_i-1$或者$a_i-2$存在于数组中
现在要你构造一个元素和为$s$的数组,问最短长度为多少
分析
贪心,让数组元素尽量大,但是因为$a_i-2$必须在数组中,所以构造的是$1,3,5,7,…$. 最后一个数如果溢出可以将其减小至和恰好为$s$,不影响性质。
代码
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
| #include <bits/stdc++.h> #define fors(i, a, b) for(int i = (a); i <= (b); ++i) #define lson k<<1 #define rson k<<1|1 #define pb push_back #define lowbit(x) ((x)&(-(x))) #define mem(a) memset(a, 0, sizeof(a)) #define DDLC_ESCAPE_PLAN_FAILED ios::sync_with_stdio(false), cin.tie(0) #define int long long const int inf = 0x3f3f3f3f; const double dinf = 1e100; typedef long long ll;
using namespace std; signed main() { DDLC_ESCAPE_PLAN_FAILED; int t; cin >> t; while(t--) { int sum = 0; int n; cin >> n; for(int i = 1; ; i += 2){ sum += i; if(sum >= n){ cout << (i + 1) / 2 << endl; break; } } } return 0; }
|
B. Maximum Cost Deletion
题意
给一个01串。每次操作可以选其中连续一段由相同字符构成的子串并将其删除。删除后剩下的部分保留顺序,拼接起来。每次删可以得到$a·l+b$分($l$为删的长度)。问删完后最大得分是多少
分析
考虑串中每个元素的平均贡献,即$\frac{a·l+b}{l}=a+\frac{b}{l}$. 由此可知不管怎么删,每个元素都一定会贡献$a$分。有变数的只有$b$. 当$b\geq 0$,应让$l$尽量小来最大化分数,所以$l=1$,答案是$总长度·(a+b)$;而若$b<0$,尽量让$l$变大。所以尽可能地扩展长度,每次都把整个连续的串删掉。
这个时候,把字符串分成$x$块,每块都是最长的连续的0或者1,这些块的邻居肯定是不同字符。每次删除之后,相邻字符会拼接起来。每次一个块一个块地删,最后总共删$x/2+1$次. 则答案为$a·l+(x/2+1)·b$
代码
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
| #include <bits/stdc++.h> #define fors(i, a, b) for(int i = (a); i <= (b); ++i) #define lson k<<1 #define rson k<<1|1 #define pb push_back #define lowbit(x) ((x)&(-(x))) #define mem(a) memset(a, 0, sizeof(a)) #define DDLC_ESCAPE_PLAN_FAILED ios::sync_with_stdio(false), cin.tie(0) #define int long long const int inf = 0x3f3f3f3f; const double dinf = 1e100; typedef long long ll;
using namespace std; signed main() { DDLC_ESCAPE_PLAN_FAILED; int t; cin >> t; while(t--) { int n, a, b; string s; cin >> n >> a >> b >> s; if(b > 0){ cout << (int)s.size() * (a + b) << endl; } else{ char now = '.'; int cnt = 0; for(int i = 0; i < s.size(); ++i){ if(s[i] != now){ now = s[i]; cnt++; } } cout << (cnt / 2LL + 1LL) * b + a * (int)s.size() << endl; } } return 0; }
|
C. Manhattan Subarrays
题意
给数组$a$,则规定其对应了平面上$n$个点$(a_1,1),(a2,2),…(a_i,i)…$ 现在要求选出一个连续子数组,保证其长度小于3,或者从其中任选3个点$x,y,z$,不可能有$d(x,y)+d(y,z)=d(x,z)$。其中$d(x,y)$为$(a_x,x)$和$(a_y,y)$的曼哈顿距离](https://baike.baidu.com/item/曼哈顿距离/743092)),问可选出多少这样的子数组。
分析
由于各个点的$y$坐标都不一样,可以画图。随意在坐标图上画3个$y$坐标两两不同的点,改变它们$x$坐标之间的关系。可以发现,当按$y$坐标顺序看这三个点时,当且仅当它们的$x$坐标单调不下降或者单调不上升时,有$d(x,y)+d(y,z)=d(x,z)$。
那么对于长度为4的子数组,我们需要判断4次,每次从其中任选3个判断一下。
但对于长度5的数组,我们发现,不管怎么画,都必定会出现$d(x,y)+d(y,z)=d(x,z)$。
因此,满足条件的数组最长长度为4。而长度为2,1的必定符合条件,故我们只需判断长度为3,4的即可。
代码
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
| #include <bits/stdc++.h> #define fors(i, a, b) for(int i = (a); i <= (b); ++i) #define lson k<<1 #define rson k<<1|1 #define pb push_back #define lowbit(x) ((x)&(-(x))) #define mem(a) memset(a, 0, sizeof(a)) #define DDLC_ESCAPE_PLAN_FAILED ios::sync_with_stdio(false), cin.tie(0) #define int long long const int inf = 0x3f3f3f3f; const double dinf = 1e100; typedef long long ll;
using namespace std; const int maxn = 2e5 + 10; int a[maxn]; bool check(int x, int y, int z) { if(a[x] <= a[y] && a[y] <= a[z]) return 0; if(a[x] >= a[y] && a[y] >= a[z]) return 0; return 1; } signed main() { DDLC_ESCAPE_PLAN_FAILED; int t; cin >> t; while(t--) { int n; cin >> n; fors(i, 1, n) cin >> a[i]; int ans = 2 * n - 1; for(int len = 3; len <= 4; ++len){ for(int l = 1; l + len - 1 <= n; ++l){ if(len == 3 && check(l, l + 1, l + 2)) ans++; else if(len == 4 && (check(l, l + 1, l + 2) && check(l, l + 2, l + 3) && check(l + 1, l + 2, l + 3) && check(l, l + 1, l + 3))) ans++; } } cout << ans << endl; } return 0; }
|