目录
A. Beat The Odds
思路:如果数组中即存在奇数,又存在偶数,则必定存在两数之和为奇数的情况,所以,数列必须全奇数或者全偶数,我们的目的,找到数组中奇数的个数,与偶数的个数,取 min 输出即可
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
typedef pair<char, int> PCI;
typedef long long LL;
const int N = 2e5+10;
int T;
LL gcd(LL a, LL b)
{
return b ? gcd(b, a % b) : a;
}
void solve()
{
int n;
int a[N];
string s;
scanf("%d", &n);
int x, resa = 0, resb = 0;
for(int i = 0; i < n; i ++ )
{
scanf("%d", &x);
if(x%2) resa ++;
else resb ++;
}
cout << min(resa, resb) << endl;
return;
}
int main()
{
scanf("%d", &T);
while(T -- )
solve();
return 0;
}
B. Shoe Shuffling
思路:若令本人的鞋码与大于本人的鞋交换,则最后一个人的鞋子会变小,即,该方案不成立
若令相同鞋码的人交换,则成立;所以我们的思路是:令相同鞋码的人两两交换,最后判断是否每个人都成功交换,
令 a[i] 表示交换过的鞋码,若没有人交换则a[i] == i ,如此来判断是否有人没交换, 用 mp[x] 表示当前的 x 码的鞋子的最后一个人的编号,若 x 鞋码再次出现,则令 mp[x] 保存的鞋码的编号与本次的编号交换,并更新 mp[x]
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
typedef pair<char, int> PCI;
typedef long long LL;
const int N = 2e5+10;
int T;
LL gcd(LL a, LL b)
{
return b ? gcd(b, a % b) : a;
}
void solve()
{
int n;
int a[N] = {0};
string s;
scanf("%d", &n);
map<int, int> mp;
int x;
int f = 0;
for(int i = 1; i <= n; i ++ )
{
a[i] = i;
scanf("%d", &x);
if(mp[x] == 0) mp[x] = a[i];
else
{
swap(a[mp[x]], a[i]);
mp[x] = a[mp[x]];
}
}
for(int i = 1; i <= n; i ++ )
{
if(a[i] == i)
{
puts("-1");
return;
}
}
for(int i = 1; i <= n; i ++ )
{
cout << a[i] << " ";
}
puts("");
return;
}
int main()
{
scanf("%d", &T);
while(T -- )
solve();
return 0;
}
C. Sum of Substrings
思路:可判断知道,字符串的开头的 1 对结果贡献 10 ,字符串的结尾的 1 对结果贡献 1 ,其余部分的 1 对结果贡献为 11,如此我们仅需判断是否有足够的 移动次数,先使字符串最后一个 1 移动到字符串结尾的位置,然后再使第一个 1 移动到字符串开头的位置,如此可最大程度的减小 1 对结果的贡献
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
typedef pair<char, int> PCI;
typedef long long LL;
const int N = 2e5+10;
int T;
LL gcd(LL a, LL b)
{
return b ? gcd(b, a % b) : a;
}
void solve()
{
int n, m;
LL res = 0;
string s;
scanf("%d %d", &n, &m);
cin >> s;
int a[N], cnt = 0;
for(int i = 0; i < s.size(); i ++ )
{
if(s[i] == '1') a[cnt++] = i, res += 11;
}
// 特例只有 0
if(cnt == 0)
{
cout << 0 << endl;
return ;
}
// 特例只有一个 1 ,只判断移动到末尾或移动到开头,防止这个 1 既移动到末尾,又移动到开头
if( m >= n - a[cnt-1] - 1)
{
res -= 10, m -= n - a[cnt-1] - 1;
if(cnt == 1)
{
cout << res << endl;
return;
}
}
if( m >= a[0] ) res --, m -= a[0];
cout << res << endl;
return;
}
int main()
{
scanf("%d", &T);
while(T -- )
solve();
return 0;
}
D. Max GEQ Sum
思路:单调栈 + st表(st表存前缀和)
根据每个 a[i] ,用单调栈找到以 a[i] 为最大值的最大区间( L[ i ] + 1, R[ i ] - 1 ) ,判断目标区间中的最大区间和是否大于 a[i] 即可,若大于,则不成立,反之成立
最大区间和求法:以 i 为分界线,后半段的最大值 - 前半段的最小值,利用前缀和求目标区间的最大值,(后半段至少比前半段多 w[i] ,当元素组的 i 的后半段全小于零时)
注意:初始化 st表 时 从 0 开始初始化,因为不仅求max 还有 min ,求 max 时,预处理数组0处的0不妨碍求 max,求 min 时,可能前半段的最小值为 0 即,前半段的数组元素都不选择,此时,若不预处理0,结果无法取到0)
求前半段时 querymin( l1 - 1, i - 1) ,此处的 l1 - 1 是取 0 的情况( L[i] 一定是第一个大于 a[i] 的数,但也可能是 索引为 0 的 0 元素),若 L[i] 是0元素,则最小值为 0 ,这也是为什么初始化 st表时要从0开始的原因
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
typedef pair<char, int> PCI;
typedef long long LL;
const int N = 2e5+5, M = 20;
int T;
int n, w[N];
LL s[N];
LL fmx[N][M], fmi[N][M];
void init()
{
for(int j = 0; j < M; j ++ )
for(int i = 0; i + (1 << j) - 1 <= n; i ++ )
if(!j) fmx[i][j] = fmi[i][j] = s[i];
else
{
fmx[i][j] = max(fmx[i][j-1], fmx[i + (1 << j - 1)][j-1]);
fmi[i][j] = min(fmi[i][j-1], fmi[i + (1 << j - 1)][j-1]);
}
}
LL querymx(int l, int r)
{
int k = log2(r - l + 1);
return max(fmx[l][k], fmx[r - (1 << k) + 1][k]);
}
LL querymi(int l, int r)
{
int k = log2(r - l + 1);
return min(fmi[l][k], fmi[r - (1 << k) + 1][k]);
}
void solve()
{
scanf("%d", &n);
for(int i = 1; i <= n; i ++ )
{
scanf("%d", &w[i]);
s[i] = s[i-1] + w[i];
}
init();
int l[N], r[N];
stack<int> stk;
for(int i = 1; i <= n; i ++ )
{
while(stk.size() && w[stk.top()] <= w[i]) stk.pop();
if(stk.size()) l[i] = stk.top();
else l[i] = -1;
stk.push(i);
}
while(stk.size()) stk.pop();
for(int i = n; i >= 1; i -- )
{
while(stk.size() && w[stk.top()] <= w[i]) stk.pop();
if(stk.size()) r[i] = stk.top();
else r[i] = -1;
stk.push(i);
}
for(int i = 1; i <= n; i ++ )
{
int l1 = (l[i] == -1 ? 1: l[i] + 1);
int r1 = (r[i] == -1 ? n: r[i] - 1);
if(l1 == r1) continue;
//printf("i : %d w[i] : %4d l1 : %4d r1 : %4d\n", i, w[i], l1, r1 );
if( querymx(i, r1) - querymi(l1 - 1, i - 1) - w[i] > 0 )
{
//printf("i : %d %lld %lld %d\n", i, querymx(i, r1), querymi(l1-1, i-1), w[i]);
//printf("i : %d %lld %lld %d\n", i, querymx(i, r1), querymi(l1, i-1), w[i]);
puts("NO");
return;
}
}
puts("YES");
return;
}
int main()
{
scanf("%d", &T);
while(T -- )
solve();
return 0;
}