cf551-brother_acm训练题解

本文讨论了Serval的问题,涉及使用贪心算法解决有根树中节点操作和数值分配问题,以及如何在01串题目中通过构造和检查合法序列来确保满足特定条件。核心内容包括二分法求最小时间、三视图问题的判定、01串的构造技巧,以及有根树中节点操作的优化策略。
摘要由CSDN通过智能技术生成

A.二分来做,求出每个路线能承载seval 的最小时间,所有路线的最小时间就是答案。

B.高中里的三视图,给你其中两个,和俯视方块存在的0/1矩阵,让你找到一种填充方式,

判定就是存在?min(h(俯视),h(正视)) :0;

C.01串题,把括号序列()看成0、1,(+1,-1)类似于卡特兰数的01串,S的所有严格前缀中0的个数要严格大于1的个数(也就是+1的个数要严格大于-1的个数)字符串中第一个字符一定是不是")",最后一个字符一定不是"(",且长度一定是偶数,这样就能构造出形如“(???????)”的字符串,为了中间的n-2个字符合法,贪心的把先放cnt=(n-2)/2“(”这样构造出的子串会尽可能的合法,此外,一旦中间这一部分出现了“(”,就让cnt--;其余的?都换成”)” 就可以了,最后判断构造出的字串是否合法,合法就输出,不合法就输出“:(”。

code:

#include<bits/stdc++.h>
using namespace std;
//贪心优先放(
signed main(){
  int n;
  cin>>n;
  string s; 
  cin>>s;
  int sum=0;
     if(s[0]==')'||s[n-1]=='('||n%2==1) {
        cout<<":)"<<endl;
     }else{
      int cnt=n/2;
      for(int i=0;s[i];i++) if(s[i]=='(') cnt--;
      for(int i=0;s[i];i++){        
        if(s[i]=='?'){
            if(cnt) {
                s[i]='(';
                cnt--;
            }else s[i]=')';
        }
      }

     }
     int flag=1;
     for(int i=0;i<n-1;i++){
       sum+=s[i]=='('?-1:1;
       if(sum>=0) flag=0;
    }
    cout<<(flag?s:":(")<<endl;
    return 0;
}

D:塞维尔和他的有根树......

Serval拥有的根树有n个节点,节点1是根。Serval会将一些数字写入树的所有节点。然而,也有一些限制。除叶子以外的每个节点都写有一个操作max或min,表示该节点中的数字应该分别等于其子节点中所有数字的最大值或最小值。

首先,贪心的考虑,假设对于非叶子节点x xx:
1.当该节点的操作为m a x 时:该点的值为叶子节点的最大值。
2.当该节点的操作为m i n 时:该点要尽可能的取到最大值。
这时候要尽可能的把大的放到叶子节点数量少的点。

比如这个图,假设1 , 2 , 3 , 4 节点的值都是m i n,那么考虑如何分配是最优的:
就是把大的尽可能分给12 , 13 。
实现起来就很思维了。
数组d[i]维护的是以i ii为根节点的子树中叶子节点的数值排名d[i]大的数值。
比如该节点x下有6个叶子节点,d [ x ] = 2 ,表示这个节点最大可以是6-2+1=5,也就是第二大的数。

///#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PLL;
typedef pair<int, int>PII;
typedef pair<double, double>PDD;
#define I_int ll
inline ll read(){ll x = 0, f = 1;char ch = getchar();while(ch < '0' || ch > '9'){if(ch == '-')f = -1;ch = getchar();}while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}return x * f;}
#define read read()
#define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define multiCase int T;cin>>T;for(int t=1;t<=T;t++)
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define perr(i,a,b) for(int i=(a);i>(b);i--)
ll ksm(ll a, ll b, ll p){ll res = 1;while(b){if(b & 1)res = res * a % p;a = a * a % p;b >>= 1;}return res;}
const int inf = 0x3f3f3f3f;
#define PI acos(-1)
const double eps = 1e-8;
const int maxn = 3e5 + 7,mod=1000000007;
int d[maxn],a[maxn];
vector<int>g[maxn];
int n,cnt=0;
void dfs(int u){
	if(!g[u].size()){
		d[u]=1;
		cnt++;
		return ;
	}
	if(a[u]) d[u]=n;
	else d[u]=0;
	for(int t:g[u]){
		dfs(t);
		if(a[u]) d[u]=min(d[u],d[t]);
		else d[u]+=d[t];
	}
}
int main(){
	n=read;
	rep(i,1,n) a[i]=read;
	rep(i,2,n){
		int x=read;
		g[x].push_back(i);
	}
	dfs(1);
	cout<<cnt+1-d[1]<<endl;
	return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

litian355

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值