A. Lucky?
水题
#include<bits/stdc++.h>
using namespace std;
int main()
{
int T;
cin >> T;
while(T--)
{
string str;
cin >> str;
int sum = 0;
for(int i = 0;i < 3;i++) sum += str[i]-'0';
for(int i = 3;i < str.size();i++) sum -= str[i] - '0';
if(sum == 0) puts("YES");
else puts("NO");
}
return 0;
}
B. Equal Candies
思路:记录最小值 将每个值减去最小值累加起来就是ans
#include<bits/stdc++.h>
using namespace std;
const int N = 50;
typedef long long LL;
int a[N];
int main()
{
int T;
cin >> T;
while(T--)
{
int n;
cin >> n;
int minv = 1e9;
for(int i = 0;i < n;i++)
{
cin >> a[i];
minv = min(a[i],minv);
}
int sum = 0;
for(int i = 0;i < n;i++)
{
sum += a[i] - minv;
}
cout << sum << endl;
}
return 0;
}
C. Most Similar Words
思路:对于每位的字母相减求绝对值 累加 就是ans
#include<bits/stdc++.h>
using namespace std;
const int N = 100;
typedef long long LL;
int a[N];
int main()
{
int T;
cin >> T;
while(T--)
{
int n,m;
cin >> n >> m;
string str[N];
for(int i = 1;i <= n;i++) cin >> str[i];
int minv = 1e9;
for(int i = 2;i <= n;i++)//从第二个开始
{
string a = str[i];
for(int j = 1;j < i;j++)//只需要枚举1~i的即可
{
int sum = 0;
for(int k = 0;k < m;k++)//枚举每一位的差的绝对值
{
int x = str[i][k] - 'a';
int y = str[j][k] - 'a';
sum += abs(x - y);
}
minv = min(sum,minv);//更新一下最小值
}
}
cout << minv << endl;
}
return 0;
}
D. X-Sum
思路:
1.先记录每条副对角线 和 主对角线 上元素的和
2.再枚举象所在的位置 对角线上的和-所在位置的元素(因为多算了一次)
3.每次更新最大值得到ans
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 205, M = 405;
int a[N][N];//存储矩阵
int dg[M],udg[M];//dg存储主对角线的和 udg存储副对角线的和
//若有n行m列 那么对角线的个数是n+m-1 ,所以空间要开到405
int n,m;
void init()
{
memset(dg,0,sizeof dg);
memset(udg,0,sizeof udg);
}
int main()
{
int T;
cin >> T;
while(T--)
{
init();//每次要清空对角线的和的数组
cin >> n >> m;
int t = max(n,m);
for(int i = 1;i <= n;i++)
for(int j = 1;j <= m;j++)
{
cin >> a[i][j];
dg[i+j] += a[i][j];//对于主对角线而言 对角线上的点满足i+j相等
udg[i - j + t] += a[i][j];//对于副对角线而言 对角线上的点 满足i-j相等
//为了避免负索引的出现 加上一个偏移量max(n,m)
}
int maxv = 0;//记录最大和
//枚举象的位置
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= m;j++)
maxv = max(maxv,dg[i+j] + udg[i-j+t]-a[i][j]);
}
cout << maxv << endl;
}
return 0;
}
E. Eating Queries
思路:
1.先将所以的糖降序排序 求一遍前缀和
2.再二分出 第一个大于询问值的下标(即是答案)
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 150010;
int a[N];
int s[N];//前缀和数组
int n,Q;
int find(int x)
{
int l = 1,r = n;
while(l < r)
{
int mid = l + r >> 1;
if(s[mid] >= x) r = mid;//找到第一个大于等于x的值
else l = mid + 1;
}
if(s[r] >= x) return r;//满足题意则返回r
return n+1;//不然返回一个大于n的数
}
int main()
{
int T;
cin >> T;
while(T--)
{
memset(a,0,sizeof a);
memset(s,0,sizeof s);
cin >> n >> Q;
for(int i = 1;i <= n;i++)
{
cin >> a[i];
}
//先从小到大排序 再翻转一下(主要是不会从大到小排)
sort(a+1,a+n+1);
reverse(a+1,a+n+1);
for(int i = 1;i <= n;i++) s[i] = s[i-1] + a[i];
while(Q--)
{
int maxv;
cin >> maxv;
int ans = find(maxv);
if(ans>=1 && ans <= n) cout << ans << endl;
else puts("-1");
}
}
}
F. Longest Strike
思路:
1.用map统计数出现的个数 将a数组的元素简化成都不重复的元素
2.从头遍历 a数组 双指针判断满足题意的解
3.更新最大区间长度 和 左右端点值(具体细节看代码)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
const int N = 200010;
int a[N],idx;
map<int,int>b;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
b.clear();//每次将map清空
int n,k;
idx = 0;//将idx置为0 统计不重复数的个数
cin >> n >> k;
for(int i = 1;i <= n;i++)
{
int x;
scanf("%d",&x);
if(b.count(x)) b[x] ++;//x出现过就累加
else
{
a[idx++] = x;//第一次出现就存到a中
b[x] = 1;//次数置为1
}
}
sort(a,a+idx);//对a数组从小到大排序
//方便后续操作(因为满足题目要求的是严格递增的序列 中间不能少值)
int ans = 0;//记录满足区间的最大长度
int l = 0,r = 0;//记录左右端点的值
for(int i = 0;i < idx;i++)
{
if(b[a[i]]>=k)//当a[i]个数大于等于k 进入判断
{
int j=i;
//判断下标有没有越界 再判断前后是否满足递增(指的是+1的关系) 再判断下一个值个数是否大于等于k
//满足则j++
while(j + 1 < idx && (a[j+1] - a[j]==1) && b[a[j+1]]>=k) j++;
//更新一下答案
if((a[j]-a[i]+1)>ans)
{
ans=a[j]-a[i]+1;
l=a[i];
r=a[j];
}
i=j;//跳出循环的时候a[j]是不满足题意的 但是i自己会++ 所以赋值为j
}
}
if(ans != 0) cout << l << " " << r << endl;
else puts("-1");
}
return 0;
}
G. White-Black Balanced Subtrees
思路:使用邻接表存整个树,dfs将儿子的信息传递给父节点(具体看代码)
样例说明:
1 1 2 3 3 5(表示2号3号是一号节点的儿子,4号是2号的儿子....)
WBBWWBW(依次为1~n的颜色)
#include<iostream>
#include<algorithm>
#include<cstring>
const int N = 4010;
int e[N],ne[N],h[N],idx;
int f[N][2];//f[i][0] 表示以i为父节点的子节点的白色数量
//f[i][1] 表示以i为父节点的子节点的黑色数量
int ans;
void init()//多组测试数据因此要初始化上一次用过的数据
{
memset(e,0,sizeof e);
memset(ne,0,sizeof ne);
memset(h,-1,sizeof h);//表头数组初始化为-1
memset(f,0,sizeof f);
idx = 0;
ans = 0;
}
//e存的是编号 ne存的是儿子的编号 h是头节点
void add(int a,int b)//加边函数 建立一条从a到b的边
{
e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}
void dfs(int u)
{
//遍历根节点的儿子节点
for(int i = h[u];~i;i = ne[i])
{
int j = e[i];
dfs(j);//计算儿子节点的黑白节点数(一直到叶子节点之和 开始回溯 子节点的信息传递给父节点)
f[u][0] += f[j][0];//更新父节点的白节点数
f[u][1] += f[j][1];//更新父节点的黑节点数
}
if(f[u][1] == f[u][0]) ans ++;//如果根节点的黑节点数等于白结点数 ans ++;
}
int main()
{
int T;
cin >> T;
while(T--)
{
init();
int n;
cin >> n;
for(int i = 2;i <= n;i++)
{
int x;
cin >> x;
add(x,i);
}
for(int i = 1;i <= n;i++)
{
char c;
cin >> c;
f[i][c == 'B'] = 1;
}
dfs(1);//从根节点开始dfs
cout << ans << endl;
}
}
H1. Maximum Crossings (Easy Version)
简单版本的思路:
从前往后看一下 每个数前面大于等于他的数的个数有多少 时间复杂度是O(n^2)数据范围是1000 能过
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1010;
int a[N];
int main()
{
int T;
cin >> T;
while(T--)
{
int n;
cin >> n;
memset(a,sizeof a,0);
for(int i = 0;i < n;i++) cin >> a[i];
int ans = 0;
for(int i = 0;i < n;i++)
{
for(int j = i-1;j >=0;j--)
{
if(a[j] >= a[i]) ans++;
}
}
cout << ans << endl;
}
}
H2. Maximum Crossings (Hard Version)
思路:
1.题目数据范围开到了2e5 提示我们只能用O(n) 或者O(nlogn)的复杂度解决
2.我们每次想看当前这个数之前 有多少个数比他大 ,也就是我们每次读进来数都要记录一下
题目又说读进来的数小于等于2e5
3.所以我们每次读进来一个数x 先算一下大于x数的个数有多少 再在x的位置上+1
4.每次单点修改 区间求和 不免想到树状数组(经典的树状数组求逆序对)
5.记得对ans开LL不然会WA
〔manim | 算法 | 数据结构〕 完全理解并深入应用树状数组 | 支持多种动态维护区间操作_哔哩哔哩_bilibili
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 200010;
int tr[N];
int n;
typedef long long LL;
int lowbit(int x)
{
return x & -x;
}
void add(int x,int c)
{
for(int i = x;i<= n;i+=lowbit(i)) tr[i] += c;
}
LL ask(int x)
{
LL res = 0;
for(int i = x;i > 0;i-=lowbit(i)) res += (LL)tr[i];
return res;
}
int main()
{
int T;
cin >> T;
while(T--)
{
cin >> n;
memset(tr,0,sizeof tr);
LL ans = 0;
for(int i = 1;i <= n;i++)
{
int a;
cin >> a;
ans = ans + ask(n) - ask(a-1);
add(a,1);
}
cout << ans << endl;
}
}