牛客练习赛58

牛客练习赛58

C-矩阵消除游戏

在这里插入图片描述
在这里插入图片描述
题解:看到题目首先想到的应该是按照题意贪心——每次找行或列中元素和最大的,然后元素值变为零,循环k次。但这样的贪心是错的。
比如:

3 3 2
100 100 1
10 10 1
10 10 1
贪心:(100+100+1)+(10+10+1)=222
答案:(100+10+10)+(100+10+10)=240

每次贪心后元素的值变零对之后的选择产生了影响,使最终结果产生错误。
再看n和m如此之小,所以可以采用枚举寻找最大值,在此我们使用二进制枚举枚举所有方案。
AC码:

#include<bits/stdc++.h>

using namespace std;
typedef long long LL ;

LL  n,m,k;
LL a[20][20],b[20][20];

void copy(){
	for(int i=0;i<n;i++)
	for(int j=0;j<m;j++)
	b[i][j] = a[i][j];
}
int main()
{
	int ans=0;
	cin>>n>>m>>k;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			cin>>a[i][j];
			ans+=a[i][j];
		}
	}
	if(k>=n||k>=m) {
		cout<<ans<<endl;	//全选
		return 0;
	}else ans = 0 ;
	
	for(int i=0; i< 1<<n ;i++) {  	//二进制枚举;
		int num=0,vis[20],cnt=0;
		for(int j = 0 ;j<n;j++){
			if((i>>j) & 1) vis[cnt++] = j;
		}
		if(cnt<=k) {
			copy();
			for(int c=0;c<cnt;c++)   // 注意下标
				for(int cc=0;cc<m;cc++)
					num+=b[vis[c]][cc] , b[vis[c]][cc] = 0;
			int sum[20]={0};
			for(int c=0;c<m;c++)   //注意下标
				for(int cc=0;cc<n;cc++) 
					sum[c]+=b[cc][c];
			sort(sum,sum+m);
			int kk = k-cnt;
			for(int c=m-1;c>=0&&kk>0;c--){
				num+=sum[c];kk--;
			}
			ans = max(ans, num);
		}
	}
	cout<<ans<<endl;
	return 0;
 } 

D-迷宫

在这里插入图片描述
在这里插入图片描述
分析一波: 虽然题意描述每个格子有四个方向可以走,但是由于题目设定了方向优先级,经过分析每个格子只能往右或往下走: 因为若是往左走后, 那他的右边就是空的了,下一步他又会往右走。同理也不能往上走。所以此问题就化简成了经典的DP问题(矩阵取数)了。

#include<bits/stdc++.h>

using namespace std;
const int INF = 0x3f3f3f3f;

char G[1010][1010];
int dp[1010][1010];
int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>G[i]+1;
	memset(dp,INF,sizeof dp);  //初始化dp矩阵用于判断是否达到终点且dp使用的是min;
	dp[1][1] = 0;  //开始置零;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(G[i][j]=='0'){
				if(G[i-1][j]=='0') dp[i][j] = min(dp[i][j],dp[i-1][j]+(G[i-1][j+1]=='0'));  //从上边来
				if(G[i][j-1]=='0') dp[i][j] = min(dp[i][j],dp[i][j-1]);	 //从右边来
			}
		}
	}
	if(dp[n][m]!=INF) cout<<dp[n][m]<<endl;
	else cout<<-1<<endl;
	return 0;
}

E - 最大GCD

在这里插入图片描述
在这里插入图片描述
题解:题意:在 [l,r] 内寻找 一个数和x的gcd最大。vector < int > pos[N] 以因子为下标,储存元素出现的位置(该因子为元素的因子之一) ,后将位置排序,再以x的因子p从大到小判断pos[p] 中的下标是否在 [l,r] 区间内。详情请看注释。
AC码:

#include<bits/stdc++.h>

using namespace std;
const int N = 1e5+7;

int n,q,t;
vector<int> pos[N];

int main()
{
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++){		//将输入的数组预处理(拆分); 
		scanf("%d",&t);
		for(int j=1;j<=sqrt(t);j++){  //求一个数的因子;
			if(t%j==0){
				pos[j].push_back(i);  //pos[j] 储存某数的因子之一是j的数的下标; 
				if(t/j!=j) pos[t/j].push_back(i);
			}
		}
	}
	for(int i=1;i<=n;i++) sort(pos[i].begin() ,pos[i].end());  // 将下标排序,方便二分查找
	
	while(q--){
		int l,r,x;
		vector<int> ans; 
		scanf("%d%d%d",&l,&r,&x);
		for(int i=1;i<=sqrt(x);i++){
			if(x%i==0){
				ans.push_back(i); 
				if(x/i!=i) ans.push_back(x/i); 
			}
		}
		sort(ans.begin() ,ans.end() ,greater<int>());  // 将x的因子从大到小排序,一旦符合即结果
		for(int i=0;i<ans.size() ;i++){
			t = upper_bound(pos[ans[i]].begin() ,pos[ans[i]].end() , r) - lower_bound(pos[ans[i]].begin() ,pos[ans[i]].end() , l); 
			if(t){		//可用于查找某个数或区间是否存在,若存在t>0,否则 t = 0 = pos[].end() - pos[].end();
				printf("%d\n",ans[i]);
				break;
			}
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值