ACwing第17周周赛题解

3971.最小的商

题目意思:

给定n个数字和一个数字k,找到这n个数字中能被k整除的最大值

题目思路:

暴力遍历一遍即可

#include <bits/stdc++.h>
#define FAST std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
typedef long long ll;
int T;
int n,m;
const int maxn = 1e5 + 10;
int main()
{
	cin >> T;
	while(T--){
		cin >> n >> m;
		int tmp;
		int ans = maxn;
		for(int i = 1;i <= n;i++)
		{
			cin >> tmp;
			if(m % tmp == 0) ans = min(ans ,m / tmp);
		}
		cout << ans <<"\n";
	}
	return 0;
}

3972 方格集合数量

题目大意:

在一个n * m的棋盘中,每个位置有一个数字可能是0,可能是1

每一行和每一列数值相同的元素可以组成一个集合

求这个集合的数量

解题思路:

根据题目可得,假设一行的数字分别是 1 0 1 0 1,那么1组成的集合应该是 {1}(第一个1),{1}(第三个1),{1}(第5个1),然后组成2个1的集合是3个,组成3个1的集合是1个,因此可以用组合计数的方式去进行计算

注意行列计算的时候,比如Ctmp取1是在行列中都取过,所以最后需要减去一次n * m的数量

#include <bits/stdc++.h>
#define FAST std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
typedef long long ll;
const int maxn = 1e2 + 10;
ll mp[maxn][maxn];
ll ans;
ll a[62];
int n,m;
void pre()
{
	a[1] = 1;
	for(int i = 2;i <= 50;i++) a[i] = 2 * a[i - 1] + 1;
}

int main()
{
	pre();
	cin >> n >> m;
	for(int i = 1;i <= n;++i)
	{
		for(int j = 1;j <= m;++j) cin >> mp[i][j];
	}
//	ans += n * m;
	for(int i = 1;i <= n;i++)
	{
		int tmp = 1;
		for(int j = 2;j <= m;j++)
		{
			if(mp[i][j] == mp[i][1]) tmp++;
		}
		//cout << a[tmp] <<" "<<a[m - tmp]<<"\n";
		ans += a[tmp];
		ans += a[m - tmp];
		//if(tmp > 0) ans -= tmp * 2;
	}
	for(int j = 1;j <= m;++j)
	{
		int tmp = 1;
		for(int i = 2;i <= n;++i)
		{
			if(mp[i][j] == mp[1][j]) tmp++;
		}
		//cout <<"tmp"<<tmp<<"\n"; 
		//cout << a[tmp] <<" "<< a[n - tmp]<<"\n";
		ans += a[tmp];
		ans += a[n - tmp];
		//ans -= tmp * 2;
	}
	ans -= n * m;
	//if(n == 1 && m == 1) ans = 1;
	cout << ans <<"\n"; 
	return 0;
}

3973.

题目大意:

给定n个牛和m个空调,空调的位置是b[i],空调的覆盖距离是[b[i] - r,b[i] + r],求最小距离能够让所有牛牛吹到空调

解题思路:

分析题目数据n是1e5,同时最大距离是2e9,那么常规暴力是肯定不能行得通的

既然是求最后的距离,那么这又是一道经典的二分枚举最后数值的题目

时间复杂度大约在1e8左右

同时在二分的时候我们需要注意以下几点

1.如果牛还在目前位置到的左端点的左边,直接退出并且增加空调距离

2.如果牛在目前位置的右端点的右边,那么需要移动目前空调的坐标

3.如果所有牛牛目前都能吹到,更新答案的同时再缩小右端点

因此答案就显而易见的得出来啦

#include <bits/stdc++.h>
#define FAST std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
ll a[maxn];
ll b[maxn];
int m,n;
ll ans;
void search()
{
	ll L = 0;
	ll R = 2000000000;
	while(L <= R)
	{
		//cout <<"????"<<L<<" "<<R<<"\n";
		ll mid = (L + R) >> 1;
		int pos = 1;
		int pos2 = 1;
		while(pos <= n && pos2 <= m)
		{
			if(a[pos] >= b[pos2] - mid && a[pos] <= b[pos2] + mid)
			{
				pos++;
			}
			else if(a[pos] < b[pos2] - mid)
			{
			//	L = mid + 1;
				break;
			}
			else pos2++;
		}
		if(pos <= n) L = mid + 1;
		if(pos > n)
		{
			ans = min(ans,mid);
			R = mid - 1;
		}
	}
}
int main()
{
	FAST
	cin >> n >> m;
	for(int i = 1;i <= n;++i) cin >> a[i];
	for(int i = 1;i <= m;++i) cin >> b[i];
	ans = 2000000000;
	search();
	cout << ans <<"\n";
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值