牛客小白月赛96
A 最少胜利题数
链接:https://ac.nowcoder.com/acm/contest/84528/A
来源:牛客网
题目描述
本场小白月赛共 6 题,𝐵𝑖𝑛𝑔𝑏𝑜𝑛𝑔和𝐾𝑒𝑑𝑢𝑜𝑙𝑖打算𝑝𝑘一下,他们规定解题数目较多的一方获胜。
规定一个解题序列为长度不超过 6 且只包含𝐴、𝐵、𝐶、𝐷、𝐸、𝐹这6种字符的字符串,一个人不会重复解同一道题。
𝐵𝑖𝑛𝑔𝑏𝑜𝑛𝑔的解题序列为 𝑆1 ,𝐾𝑒𝑑𝑢𝑜𝑙𝑖的解题序列为 𝑆2 ,保证两个人的解题数目不同。
请你帮助他们计算出失败的一方若要反超胜利的一方还需要解出的题数,若不可能战胜,则输出 −1。
输入描述:
输入共两行,包含两个字符串 𝑆1 和 𝑆2(1≤∣𝑆1∣,∣𝑆2∣≤6)。
数据保证只包含𝐴、𝐵、𝐶、𝐷、𝐸、𝐹这6种字符,保证一个人不重复解题。
输出描述:
一个整数,表示失败的一方若要反超胜利的一方还需要解出的题数或 −1。
示例1
输入
ABD
ABCD
输出
2
示例2
输入
ABCDEF
ACE
输出
-1
题解
分类讨论下好了
#include<bits/stdc++.h>
using namespace std;
int main(){
string s1, s2;
cin >> s1 >> s2;
int l1 = s1.size(), l2 = s2.size();
if(max(l1,l2)==6){
cout << -1 << '\n';
}
else
cout << abs(l1 - l2) + 1 << '\n';
return 0;
}
B 最少操作次数
链接:https://ac.nowcoder.com/acm/contest/84528/B
来源:牛客网
题目描述
𝐵𝑖𝑛𝑔𝑏𝑜𝑛𝑔有一个长度为𝑛的字符串𝑆,仅包含0和1两种字符。
𝐵𝑖𝑛𝑔𝑏𝑜𝑛𝑔每次可以选择两个索引𝑖和𝑗(1≤𝑖<𝑗≤𝑛),并满足以下条件之一:
1.如果区间 [𝑖,𝑗] 中 1 的数量大于 0 的数量,可以把此区间的所有数字都变成 1。
2.如果区间 [𝑖,𝑗] 中 0 的数量大于 1 的数量,可以把此区间的所有数字都变成 0。
他想知道把整个串变成全 0 或者全 1 的最少操作次数,如果无解,输出−1。
输入描述:
第一行一个整数 𝑛(1≤𝑛≤2×105) ,表示字符串长度。
第二行一个长度为 𝑛 字符串𝑆,保证输入只含 0、1。
输出描述:
一个整数,表示最少操作次数,无解输出 −1。
示例1
输入
2
01
输出
-1
示例2
输入
3
011
输出
1
题解
看题目感觉挺唬人的,让人感觉是一道DP的题目
但是你只要稍微分析下,你会发现这道题跟数列的顺序没有任何的关系,之和0和1的个数有关,也是一道分类讨论的题目
#include <bits/stdc++.h>
using namespace std;
int n,cnt0,cnt1;
string s;
signed main()
{
int i,j,k;
cin>>n>>s;
for (i=0;i<n;i++) {
if (s[i] == '0')cnt0++;
else cnt1++;
}
if (cnt0 == 0 || cnt1 == 0) {
cout << 0 << endl;
return 0;
}
if (cnt0 != cnt1) {
cout << 1 << endl;
return 0;
}
if (s.size() == 2) cout << -1 << endl;
else cout << 2 << endl;
return 0;
}
C 最多数组数量
链接:https://ac.nowcoder.com/acm/contest/84528/C
来源:牛客网
题目描述
一个山峰数组定义为由三个元素组成 [𝑎1,𝑎2,𝑎3],满足 𝑎1<𝑎2 且 𝑎2>𝑎3 。
𝐵𝑖𝑛𝑔𝑏𝑜𝑛𝑔有一个长度为 𝑛 的数组 𝑃,他将选择两个索引 𝑖,𝑗(1≤𝑖<𝑗<𝑛),然后分成三个非空连续的子数组,即
b
1
=
∑
k
=
1
k
=
i
P
k
,
b
2
=
∑
k
=
i
+
1
k
=
j
P
k
,
b
3
=
∑
k
=
j
+
1
k
=
n
P
k
b_{1}=\sum_{k=1}^{k=i} P_{k}, b_{2}=\sum_{k=i+1}^{k=j} P_{k}, b_{3}=\sum_{k=j+1}^{k=n} P_{k}
b1=k=1∑k=iPk,b2=k=i+1∑k=jPk,b3=k=j+1∑k=nPk ,满足[𝑏1,𝑏2,𝑏3]是一个山峰数组。
𝐵𝑖𝑛𝑔𝑏𝑜𝑛𝑔想知道共有多少个不同的 (𝑖,𝑗) 可以满足条件,请你帮助他计算一下。
输入描述:
第一行一个整数 𝑛(3≤𝑛≤2×105 ),表示数组 𝑃 的长度。
第二行 𝑛 个整数,第 𝑖 个数为 𝑃𝑖(1≤𝑃𝑖≤106),表示数组元素。
输出描述:
一个整数,表示可以得到的山峰数组个数。
示例1
输入
5
1 2 3 4 5
输出
2
题解
题目看起来挺难,数据范围摆在哪里,你不可能两层循环的,对吧
那就思考怎么简便运算
首先你需要找到一个求和数组,因为Pi是正数,所以前缀和数组一定的递增的,然后你选择i然后二分的寻找符合条件的j,这样的时间复杂度可以n2变成nlogn ,可以通过此题
然后看网上还有种解法是双指针,就是一开始找到i=1满足的j的节点,然后i向后移动同时调整j的位置,这个似乎的O(n)算法吧,应该更加优秀
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MAX=200005;
int n,a[MAX],sum[MAX];
bool check(int mid,int pre){
if(sum[mid] - sum[pre] <= sum[pre] || sum[mid] - sum[pre] <= sum[n]-sum[mid])return false;
return true;
}
signed main(){
int i,j,k;
cin>>n;
for(i=1;i<=n;i++){
cin>>a[i];
sum[i]=a[i]+sum[i-1];
}
int ans = 0,now = 0;
for(i=1;i<=n;i++){
now += a[i];
int l=i,r=n;
while(l+1<r){
int mid = (l+r)>>1;
if(check(mid,i))r = mid;
else l = mid;
}
ans += n-r;
}
cout<<ans;
return 0;
}
D 最小连通代价
链接:https://ac.nowcoder.com/acm/contest/84528/D
来源:牛客网
题目描述
𝐵𝑖𝑛𝑔𝑏𝑜𝑛𝑔有 𝑛 个结点,第 𝑖 个结点的权值为 𝐴𝑖 。
初始时都为孤立的点,互不连通。
现在需要加若干条无向边,使得所有点构成一张无向连通图。
我们定义在两个结点之间加边的代价为:如果两个点的权值都是偶数或者都是奇数,代价为
𝑎。否则为 𝑏。
现在你需要帮助𝐵𝑖𝑛𝑔𝑏𝑜𝑛𝑔算出所有点构成一张无向连通图的最小代价之和。
注:加边过程中不能有重边和自环。
输入描述:
第一行一个整数 𝑇(1≤𝑇≤1000) ,表示输入的数据组数。
对于每组数据的格式为:
第一行三个整数 𝑛(1≤𝑛≤2×105),𝑎,𝑏(−100≤𝑎,𝑏≤100),表示结点个数和连通结点的不同代价。
第二行 𝑛 个整数,第 𝑖 个数 𝐴𝑖(0≤𝐴𝑖≤106) 表示第 𝑖 个结点的权值。
对于单组数据保证 ∑𝑛≤2×105 。
输出描述:
共 𝑇 行,每行 一个整数,表示所有点构成一张无向连通图的最小代价之和。
示例1
输入
2
5 1 2
0 1 2 3 4
5 100 0
1 2 3 4 5
输出
5
0
说明
对于第二组样例加边后的连通图为:
题解
有点麻烦,因为你的a和b可以是负数,所以需要多讨论讨论
说真的,一开始我以为是最小生成树,但是后来想着想着就不对劲了
这道题其实也是分类讨论的题目,讨论a,b的正负性,然后就欧了
看代码吧
#include<bits/stdc++.h>
using namespace std;
#define int long long
int T,n,a,b,s[200005],x[200005];
int find(int i)
{
if(x[i]==i)return x[i];
return x[i]=find(x[i]);
}
signed main()
{
int i,j,k;
cin>>T;
while(T--)
{
//看a还是b小
//a小 odd odd even even
//b add even 先连 然后看有几个去块
cin>>n>>a>>b;
for(i=1;i<=n;i++)
cin>>s[i]; //连通图是任意两点可以到达
int l=0,r=0;
for(i=1;i<=n;i++)
{
if(s[i]%2==0)l++;
else r++;
}
int ans=1e9; //a为负数
if(r==0||l==0) ans=min((n-1)*a,(n*(n-1)/2)*a);
else
{
if(a<=0&&b<=0)
ans=l*(l-1)/2*a+r*(r-1)/2*a+l*r*b;
else if(a<=0)
ans=l*(l-1)/2*a+(r-1)*r/2*a+b;
else if(b<=0)ans=l*r*b;
else ans=min((r-1)*a+(l-1)*a+b,(n-1)*b);
}
cout<<ans<<endl;
}
return 0;
}
E 最大稳定数值
链接:https://ac.nowcoder.com/acm/contest/84528/E
来源:牛客网
题目描述
𝐵𝑖𝑛𝑔𝑏𝑜𝑛𝑔有一棵结点总数为 𝑛 且根节点编号为 1 的有根树,第 𝑖 个结点的权值为 𝑎𝑖 。
一个结点称为"支撑结点"当且仅当其满足以下所有条件:
上层结点:除自身结点以外的祖先节点。
下层结点:除自身结点以外的子孙节点。
1.该结点的所有上层结点权值之和大于等于当前结点的权值(如果无上层结点,则其权值之和为0)。
2.该结点的所有下层结点权值之和小于等于当前结点的权值(如果无下层结点,则其权值之和为0)。
一棵有根树的稳定值为该有根树"支撑结点"的个数,为了让这棵树的稳定值达到最大,𝐵𝑖𝑛𝑔𝑏𝑜𝑛𝑔得到了一次删除树边的机会(可以不删除),即选择两个结点 𝑢,𝑣 是 𝑣 的父节点),然后把连接 𝑢,𝑣 的边删除,即把以 𝑣 为根的子树删除。请你帮助他计算出该有根树可能达到的最大稳定值。
注:当选择删除子树时,该子树的支撑结点不计入答案。
请回忆:
- 祖先结点:沿树根到某一结点路径上的所有结点都是这个结点的祖先结点;
- 子孙结点:某一结点的子树中的所有结点是这个结点的子孙;
输入描述:
第一行一个整数 𝑛(1≤𝑛≤105),表示该有根树的结点个数。
第二行包含 𝑛 个整数,第 𝑖 个数为 𝑎𝑖(1≤𝑎𝑖≤109),表示第 𝑖 个结点的权值。
第三行包含 𝑛 个整数,第 𝑖 个数为 𝑓𝑎𝑡ℎ𝑒𝑟𝑖(1≤𝑓𝑎𝑡ℎ𝑒𝑟𝑖≤𝑖−1),表示第 𝑖 个结点的父亲结点的编号,特别地 𝑓𝑎𝑡ℎ𝑒𝑟1=0。
输出描述:
一个整数,表示该有根树可能达到的最大稳定值。
示例1
输入
5
10 2 3 1 2
0 1 1 2 3
输出
4
示例2
输入
6
10 10 3 10 7 40
0 1 1 2 3 4
输出
3
备注:
对于样例一:无需删边。
对于样例二:删除结点4和结点6的边即可。
`
import java.io.BufferedInputStream;
import java.util.*;
public class Main {
static class BIT {
int n;
int[] arr;
public BIT(int n) {
this.n = n;
this.arr = new int[n + 1];
}
int query(int p) {
int res = 0;
while (p > 0) {
res += arr[p];
p -= p & -p;
}
return res;
}
void update(int p, int d) {
while (p <= n) {
this.arr[p] += d;
p += p & -p;
}
}
}
static
public class Solution {
int n;
int[] arr;
List<Integer>[]g;
long[] up;
long[] down;
int[] cs;
Map<Long, Integer> idMap = new HashMap<>();
BIT bit;
public int solve(int n, int[] arr, int[] pa) {
this.n = n;
this.arr = arr;
this.up = new long[n];
this.down = new long[n];
this.cs = new int[n];
this.g = new List[n];
Arrays.setAll(g, x->new ArrayList<>());
for (int i = 0; i < n; i++) {
if (pa[i] != -1) {
g[pa[i]].add(i);
}
}
dfs(0, -1, 0);
TreeSet<Long> ids = new TreeSet<>();
for (int i = 0; i < n; i++) {
if (up[i] - arr[i] >= arr[i] && down[i] - arr[i] > arr[i]) {
ids.add(down[i] - 2l * arr[i]);
}
ids.add(down[i]);
}
int ptr = 1;
for (long k: ids) {
idMap.put(k, ptr++);
}
this.bit = new BIT(ids.size());
dfs3(0, -1);
return gAns + cs[0];
}
int gAns = 0;
void dfs3(int u, int fa) {
int idx = idMap.get(down[u]);
int r = bit.query(idx);
r -= cs[u];
if (r > gAns) {
gAns = r;
}
if (up[u] - arr[u] >= arr[u] && down[u] - arr[u] > arr[u]) {
bit.update(idMap.get(down[u] - arr[u] * 2l), 1);
}
for (int v: g[u]) {
if (v == fa) continue;
dfs3(v, u);
}
if (up[u] - arr[u] >= arr[u] && down[u] - arr[u] > arr[u]) {
bit.update(idMap.get(down[u] - arr[u] * 2l), -1);
}
}
void dfs(int u, int fa, long pre) {
up[u] = pre + arr[u];
down[u] += arr[u];
for (int v: g[u]) {
if (v == fa) continue;
dfs(v, u, up[u]);
down[u] += down[v];
cs[u] += cs[v];
}
if (up[u] - arr[u] >= arr[u] && down[u] - arr[u] <= arr[u]) {
cs[u] += 1;
}
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
int n = sc.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
int[] pa = new int[n];
for (int i = 0; i < n; i++) {
pa[i] = sc.nextInt() - 1;
}
Solution solution =new Solution();
System.out.println(solution.solve(n, arr, pa));
}
}
`
【留个坑哈】【明天来填】