A. Find The Array
题意
要你构造一个长度为 n n n的数组,每个元素 a i a_i ai满足:
- a i = 1 a_i=1 ai=1
- a i − 1 a_i-1 ai−1或者 a i − 2 a_i-2 ai−2存在于数组中
现在要你构造一个元素和为 s s s的数组,问最短长度为多少
分析
贪心,让数组元素尽量大,但是因为 a i − 2 a_i-2 ai−2必须在数组中,所以构造的是 1 , 3 , 5 , 7 , . . . 1,3,5,7,... 1,3,5,7,.... 最后一个数如果溢出可以将其减小至和恰好为 s s s,不影响性质。
代码
#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;
//const ll linf = 9223372036854775807LL;
// const ll linf = 1e18;
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 a·l+b a⋅l+b分( l l l为删的长度)。问删完后最大得分是多少
分析
考虑串中每个元素的平均贡献,即 a ⋅ l + b l = a + b l \frac{a·l+b}{l}=a+\frac{b}{l} la⋅l+b=a+lb. 由此可知不管怎么删,每个元素都一定会贡献 a a a分。有变数的只有 b b b. 当 b ≥ 0 b\geq 0 b≥0,应让 l l l尽量小来最大化分数,所以 l = 1 l=1 l=1,答案是 总 长 度 ⋅ ( a + b ) 总长度·(a+b) 总长度⋅(a+b);而若 b < 0 b<0 b<0,尽量让 l l l变大。所以尽可能地扩展长度,每次都把整个连续的串删掉。
这个时候,把字符串分成 x x x块,每块都是最长的连续的0或者1,这些块的邻居肯定是不同字符。每次删除之后,相邻字符会拼接起来。每次一个块一个块地删,最后总共删 x / 2 + 1 x/2+1 x/2+1次. 则答案为 a ⋅ l + ( x / 2 + 1 ) ⋅ b a·l+(x/2+1)·b a⋅l+(x/2+1)⋅b
代码
#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;
//const ll linf = 9223372036854775807LL;
// const ll linf = 1e18;
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 a a,则规定其对应了平面上 n n n个点 ( a 1 , 1 ) , ( a 2 , 2 ) , . . . ( a i , i ) . . . (a_1,1),(a2,2),...(a_i,i)... (a1,1),(a2,2),...(ai,i)... 现在要求选出一个连续子数组,保证其长度小于3,或者从其中任选3个点 x , y , z x,y,z x,y,z,不可能有 d ( x , y ) + d ( y , z ) = d ( x , z ) d(x,y)+d(y,z)=d(x,z) d(x,y)+d(y,z)=d(x,z)。其中 d ( x , y ) d(x,y) d(x,y)为 ( a x , x ) (a_x,x) (ax,x)和 ( a y , y ) (a_y,y) (ay,y)的曼哈顿距离,问可选出多少这样的子数组。
分析
由于各个点的 y y y坐标都不一样,可以画图。随意在坐标图上画3个 y y y坐标两两不同的点,改变它们 x x x坐标之间的关系。可以发现,当按 y y y坐标顺序看这三个点时,当且仅当它们的 x x x坐标单调不下降或者单调不上升时,有 d ( x , y ) + d ( y , z ) = d ( x , z ) d(x,y)+d(y,z)=d(x,z) d(x,y)+d(y,z)=d(x,z)。
那么对于长度为4的子数组,我们需要判断4次,每次从其中任选3个判断一下。
但对于长度5的数组,我们发现,不管怎么画,都必定会出现 d ( x , y ) + d ( y , z ) = d ( x , z ) d(x,y)+d(y,z)=d(x,z) d(x,y)+d(y,z)=d(x,z)。
因此,满足条件的数组最长长度为4。而长度为2,1的必定符合条件,故我们只需判断长度为3,4的即可。
代码
#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;
//const ll linf = 9223372036854775807LL;
// const ll linf = 1e18;
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;
}