【蓝桥杯真题】:2023 java C组 #平均 #填充 #三国游戏 #子矩阵

 每日一题       

目录

题目:平均

思路:

问题:填充

思路:

题目:三国游戏

思路:

题目:子矩阵

思路:


        

                

题目:平均

                

问题:有一个长度为 n 的数组(n 是 10 的倍数),每个数 ai 都是区间 [0, 9] 中的整数。小明发现数组里每种数出现的次数不太平均,而更改第 i 个数的代价为bi,他想更改若干个数的值使得这 10 种数出现的次数相等(都等于n/10),请问代价和最少为多少。

        

输入格式:

输入的第一行包含一个正整数 n 。

接下来 n 行,第 i 行包含两个整数 ai , bi ,用一个空格分隔。

样例:

10
1 1
1 2
1 3
2 4
2 5
2 6
3 7
3 8
3 9
4 10

输出:

27

        

思路:

我们不用管这个数是几,只需要看它的数量,多了就删,少了就跳过,不管。这里我直接建了二维数组,这样的话,只需要跑一次排序即可,比较方便

        

#include <bits/stdc++.h>    
using namespace std;         //分类讨论
int a[10][100000],len[10];
int main(){
	long long ans=0,n,x,y;cin>>n;
	for(int i=1;i<=n;i++){
		scanf("%lld %lld",&x,&y);
		a[x][++len[x]]=y;  //引入二维数组,和长度数组
	}
	for(int i=0;i<10;i++){
		sort(a[i],a[i]+len[i]+1); //对每个一维数组排序,根据每个数组的长度
	}
	int tmp=n/10;
	for(int i=0;i<10;i++){
		for(int j=1;j<=len[i]-tmp;j++){ //不用管这个数是几,大于n/10就删就完了
			ans+=a[i][j];
		}
	}
	cout<<ans;   //不要用int
}

                

                

问题:填充

有一个长度为 n 的 01 串,其中有一些位置标记为 ?,这些位置上可以任意填充 0 或者 1,请问如何填充这些位置使得这个 01 串中出现互不重叠的 00 和 11 子串最多,输出子串个数。

输入格式:

输入一行包含一个字符串。

1110?0

输出格式:

 2

        

思路:

        

不用管?填什么,只要能凑出又一个00或11就行!!!(共3中情况)
?打头就直接ans++,i+=2
1?和0?直接ans++,i+=2
10和01  就i+=1; 11和00就ans++,i+=2

        

        

#include <bits/stdc++.h>   
using namespace std;     //分类讨论  模拟
int main(){
	string s;cin>>s;
	int ans=0,len=s.size();
	for(int i=0;i<len;){
		if(s[i]=='?')ans++,i+=2;
		else if(s[i+1]!='?'){
				if(s[i]==s[i+1]) ans++,i+=2;
				else i+=1;
			}else{
				ans++;i+=2;
			}
	}
	cout<<ans;
}

        

        

题目:三国游戏

小蓝正在玩一款游戏。游戏中魏蜀吴三个国家各自拥有一定数量的士兵X, Y, Z (一开始可以认为都为 0 )。游戏有 n 个可能会发生的事件,每个事件之间相互独立且最多只会发生一次,当第 i 个事件发生时会分别让 X, Y, Z 增加Ai , Bi ,Ci 。

当游戏结束时 (所有事件的发生与否已经确定),如果 X, Y, Z 的其中一个大于另外两个之和,我们认为其获胜。例如,当 X > Y + Z 时,我们认为魏国获胜。小蓝想知道游戏结束时如果有其中一个国家获胜,最多发生了多少个事件?

如果不存在任何能让某国获胜的情况,请输出 −1 。

        

输入格式:

输入的第一行包含一个整数 n 。

第二行包含 n 个整数表示 Ai,相邻整数之间使用一个空格分隔。

第三行包含 n 个整数表示 Bi,相邻整数之间使用一个空格分隔。

第四行包含 n 个整数表示 Ci,相邻整数之间使用一个空格分隔。

3
1 2 2
2 3 2
1 0 7

输出:

2

        

思路:

        

这个题又是一道分类讨论题,如果放在一起想任意一国赢的情况基本想不到排序,更想不到贪心,这个题和“平均 ”那个题一样,都是 分类讨论!!!
我们先处理A国:若想让A胜利,那就看每个事件的净增加人数,我们要的事件越多越好。对另外两个国家也是这样

#include <bits/stdc++.h>   
using namespace std;        //贪心
int tmp[3][100005];
struct node{
	int a,b,c;
}ar[100005];
bool cmp1(node x,node y){
	return x.a-x.b-x.c>y.a-y.b-y.c;
}
bool cmp2(node x,node y){
	return (x.b-x.a-x.c)>(y.b-y.a-y.c);
}
bool cmp3(node x,node y){
	return x.c-x.a-x.b>y.c-y.b-y.a;
}
int main(){
	int n,ans=0,cnt=0,lost=0;long long sign;
	cin>>n;
	for(int j=0;j<3;j++){
		for(int i=1;i<=n;i++)  //数据输入的方式十分奇葩
		cin>>tmp[j][i];
	}
	for(int i=1;i<=n;i++){
		ar[i].a=tmp[0][i];
		ar[i].b=tmp[1][i];
		ar[i].c=tmp[2][i];
	}
	//对A国获胜求最大事件
	sort(ar+1,ar+n+1,cmp1);
	sign=ar[1].a-ar[1].b-ar[1].c;
	if(sign>0) {
		cnt=1;
		for(int i=2;sign>0&&i<=n;i++){
		sign+=(ar[i].a-ar[i].b-ar[i].c);cnt++;
		}
		cnt--;
	}else cnt=0,lost++;
	ans=cnt;
	//对B国获胜求最大事件
	sort(ar+1,ar+n+1,cmp2);
	sign=ar[1].b-ar[1].a-ar[1].c;
	if(sign>0){
		cnt=1;
		for(int i=2;sign>0&&i<=n;i++){
		sign+=(ar[i].b-ar[i].a-ar[i].c);cnt++;
		}
		cnt--;
	}else cnt=0,lost++;

	ans=max(ans,cnt);
	//对C国获胜求最大事件
	sort(ar+1,ar+n+1,cmp3);
	sign=ar[1].c-ar[1].b-ar[1].a;
	if(sign>0){
		cnt=1;
		for(int i=2;sign>0&&i<=n;i++){
		sign+=(ar[i].c-ar[i].b-ar[i].a);cnt++;
		}
		cnt--;
	}else cnt=0,lost++;
	//特判
	if(lost==3){
		cout<<-1;return 0;
	}
	ans=max(ans,cnt);
	cout<<ans;
	return 0;
}

        

        

题目:子矩阵

给定一个 n × m (n 行 m 列)的矩阵。

设一个矩阵的价值为其所有数中的最大值和最小值的乘积。求给定矩阵的所有大小为 a × b (a 行 b 列)的子矩阵的价值的和。

答案可能很大,你只需要输出答案对 998244353 取模后的结果。

        

输入格式:

输入的第一行包含四个整数分别表示 n, m, a, b ,相邻整数之间使用一个空格分隔。

接下来 n 行每行包含 m 个整数,相邻整数之间使用一个空格分隔,表示矩阵中的每个数 Ai, j 

2 3 1 2
1 2 3
4 5 6

输出格式:

58

        

思路:

完完全全的一道裸的二维单调队列的题,直接上模板就行

#include <bits/stdc++.h>      
using namespace std;         //二维单调队列
const int mod=998244353;
long long ans;
int n,m,a,b;
long long c[1000][1000],min1[1000][1000],min2[1000][1000],max1[1000][1000],max2[1000][1000];
void print(){

	for(int i=1;i<=n-a+1;i++){//完全更新后的矩阵的行列数
		for(int j=1;j<=m-b+1;j++){
			ans=(ans+max2[i][j]*min2[i][j])%mod;  //对结果取模
		}
	}
	cout<<ans;
}
void two_deque(){ //二维单调队列
	int H,T,h,t,Q[1000]={0},q[1000]={0};
	for(int i=1;i<=n;i++){
		H=T=h=t=q[1]=Q[1]=1;
		if(b==1){  //对边长为1的特判
			memcpy(min1,c,sizeof(min1));memcpy(max1,c,sizeof(max1));break;
		}
		for(int j=2;j<=m;j++){
			while(c[i][q[t]]>c[i][j]&&h<=t) t--;q[++t]=j;
			while(c[i][Q[T]]<c[i][j]&&H<=T) T--;Q[++T]=j;
			while(q[h]+b<=j) h++;
			while(Q[H]+b<=j) H++;
			if(j>=b)min1[i][j-b+1]=c[i][q[h]],max1[i][j-b+1]=c[i][Q[H]];
		}
	}

	for(int j=1;j<=m-b+1;j++){  //注意初步更新后矩阵的行列数
		H=T=h=t=q[1]=Q[1]=1;
		if(a==1){
			memcpy(min2,min1,sizeof(min2));memcpy(max2,max1,sizeof(max2));break;
		}
		for(int i=2;i<=n;i++){
			while(min1[q[t]][j]>min1[i][j]&&h<=t) t--;q[++t]=i;
			while(max1[Q[T]][j]<max1[i][j]&&H<=T) T--;Q[++T]=i;
			while(q[h]+a<=i) h++;
			while(Q[H]+a<=i) H++;
			if(i>=a)min2[i-a+1][j]=min1[q[h]][j],max2[i-a+1][j]=max1[Q[H]][j];
		}
	}
	print();	
}
int main(){
	cin>>n>>m>>a>>b;	
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			scanf("%lld",&c[i][j]);
		}
	}
	two_deque();
	return 0;
}

        

  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值