牛客练习赛97

牛客练习赛97

1.特别的玛格丽特

每次可以交换数组中两个奇数或者两个偶数,
可以交换无数次。

思路:
分别用a,b记录下奇数和偶数的个数,当为第偶数个数字时,
如果此时奇数个数不等于偶数个数,就不行。

AC代码:

#include <bits/stdc++.h>
using namespace std;
int x,n,a,b;

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&x);
		if(x&1) a++;
		else b++;
		if(i%2==0){
			if(a!=b){
				puts("No");
				return 0;
			}
		}
		
	}
	puts("Yes");
	return 0;
}

2.野比大雄的作业

思路:
ans=[l,r]区间内所有数字的与运算的和+或运算的和,
输出ans的最大值。

尽量使[l,r]区间内的与运算和为1同时或运算和为1,
因为
&:都1为1,有0为0
|:有1为1,全0为0
因为题目没说不能为1个数,
所以能够满足题目要求的区间一定只是一个数[l,l],
即 x&x+x|x=x+x最大,
又因为x+x=x<<1,所以就是找这个数组里最大的数再*2

AC代码:
(1)C++:

#include <bits/stdc++.h>
using namespace std;
int x,ans,n;


int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&x);
		if((x<<1)>ans) ans=(x<<1);
	} 
	printf("%d\n",ans);
	return 0;
	
}

(2)Python:

input() #输入n
print(max(map(int,input().split())) * 2) #输入,以空格为分隔符,寻找输入的最大值,再将最大值*2

3.唔西迪西小姐

唔西迪西现在正处在一个冰火迷宫中,迷宫由 n
个格子组成,每个格子要么是冰之格,要么是火之格,唔西迪西刚开始可以选择从迷宫中任意一个开始走,走到第 iii 个位置时会得到值为
ai的积分。(注意:唔西迪西也可以选择一个格子都不走)

如果唔西迪西当前在冰之格,那么她可以选择一个编号大于当前格子的冰之格,跳到那里。如果唔西迪西当前在火之格,那么她可以选择一个编号大于当前格子的火之格,跳到那里。如果唔西迪西目前没有格子可以走,那么结束。同时,即使存在可以跳过去的格子,唔西迪西也可以选择在任意时刻结束。

唔西迪西想最大化她的得分,于是她学会了一个超能力,她能在比赛开始的时候改变最多 m
个格子的状态,即将一个格子从冰之格变成火之格或从火之格变成冰之格,改变第 i 个格子的状态会让唔西迪西的得分减少 pi
。(唔西迪西改变格子的状态后才开始挑选起点开始行动,也就是说,得分分成两部分,一部分是改变格子状态的得分,一部分是走格子的得分)
你能告诉唔西迪西她最多得几分吗

思路:
优先队列。

每一种格子有0/1两种状态,因为a[i]和p[i]都可能为负,
因此状态一致时可以选择走或者不走(a[i]为负时肯定选择不走啊!),
状态不一致时利用优先队列,选出>0的前m个就行了。
最后从状态0/1中选择最大的即可。

具体来说,
当状态一致时,可以有选或不选两种状态,当a[i]为负时,不选。
但是由于p[i]可能为负,等会-p[i]可能会大于a[i],这样反而会赚,
因此把-p[i]-max(0,a[i])加入队列。

状态不一致时,有选或不选两种情况。
不选的话:-p[i]
选的话:a[i]-p[i]
选择这两种的最大值加入队列。

最后在状态为0和状态为1之间选择最大值。

注意结果可能为ll,所以函数get的返回值应该为ll。

AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6+10;
int n,m,a[N],p[N],b[N];

ll get(int x){
	ll sum=0;
	priority_queue<int> q;

		for(int i=1;i<=n;i++){
			if(b[i]==x){
				sum+=max(0,a[i]);//>0时才走,小于0时不走 
			    //因为p[i]可能为负,因此可能-p[i]>a[i],此时改变这个状态可能会赚, 
				q.push(-p[i]-max(0,a[i]));//所以把-p[i]-max(0,a[i])加入队列 
			}
			else{//状态不一致时,也有选或者不选两种,不选:-p[i],选:a[i]-p[i] 
				q.push(max(-p[i],a[i]-p[i]));
			}
		}
	int cnt=0;
	while(q.size()){//取出前m大的 
		auto x=q.top();
		q.pop();
		if(cnt+1>m) break;//已经选完了前m个
		if(x<=0) break;//都已经为负数了,肯定不选啊!后面也都为负数,结束!
		sum+=x;
		cnt++;
	}
	return sum;
}

int main(){
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=n;i++) scanf("%d",&p[i]);
	for(int i=1;i<=n;i++) scanf("%d",&b[i]);
	cout<<max(get(0),get(1));
	return 0;
}

4.月之暗面

给出一棵 n个点的树,有 x 种普通颜色,y 种特殊颜色

现在要给树上的每个节点染色,普通颜色染色没有限制,但两个相邻的节点不能染相同颜色的特殊颜色

求染色方案数,答案对 998244353 取模。

思路:
树:n个节点。x种普通颜色,y种特殊颜色。
相邻两点不能为相同的特殊颜色。

树形dp;
dp[u][0]:表示父节点u取普通颜色,那么子节点颜色无限制。
则dp[u][0]*=(dp[v][0]*x+dp[v][1]y);
dp[u][1]:表示父节点取特殊颜色,那么子节点可以取普通颜色,
取特殊颜色时只能取y-1种啦,
则dp[u][1]
=(dp[v][0]x+dp[v][1](y-1));

最后答案就是(dp[1][0]*x%mod+dp[1][1]*y%mod )%mod;

一定要用ll,并且不要乱用x!

AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 998244353 ;
const int N = 1e6+10;
ll dp[N][2],x,y;
int n;
vector<int> e[N];


void dfs(int u,int fa){
	dp[u][0]=dp[u][1]=1ll;//初始化均为1 
	for(auto v:e[u]){//孩子们 
		if(v==fa) continue;//x的儿子肯定不能为x的父节点啊 
		dfs(v,u);//继续搜,此时x为它的父节点
		//对于每个节点,方案数为子节点方案数的乘积
		//x涂普通颜色 
		dp[u][0]=dp[u][0]*(dp[v][0]*x%mod+dp[v][1]*y%mod)%mod;
		//x涂特殊颜色 
		dp[u][1]=dp[u][1]*(dp[v][0]*x%mod+dp[v][1]*(y-1)%mod)%mod;
	    
	}

}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	scanf("%d %lld %lld",&n,&x,&y);
	for(int i=1;i<=n-1;i++){
		int a,b;
		scanf("%d %d",&a,&b);
		//建边 
		e[a].push_back(b);
		e[b].push_back(a);
	}
	dfs(1,0);//从1开始搜,其父节点假设为0 
	
	cout<<(dp[1][0]*x%mod+dp[1][1]*y%mod)%mod;
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值