Codeforces Round 901 (Div. 2)扫题

Jellyfish and Green Apple

本题要求将n个苹果,每次可以将一个苹果分成两半。要操作几次可以均分给m个小朋友。

首先不考虑最少操作次数,本题求出n和m的最小公倍数就可以实现均分。也就是每位小朋友可以得到gcd(n,m)/m个苹果片。每个苹果被分成了gcd(n,m)/n份。那么从被分成的份数中可以得到分成的份数必须是2的次方数。所以在这里通过b&(b-1)去除数中的最后一个1,也可以用来检测是不是2的倍数。

然后这是不考虑最小操作数的情况。考虑最小操作数就是将每位小朋友首先的苹果片给组合起来。但注意要2进制的组合。比如2可以组合。4可以组合。8可以组合。

最后将所有得苹果片数求出来来,计算多出来的苹果片数就是切了多少刀,因为每切一刀就增加一个苹果片。

#include <bits/stdc++.h>
using namespace std;
#define int long long
int gcd(int a, int b)
{
	if (b==0) return a;
	return gcd(b, a%b);
}

void solve()
{
	int n, m;
	cin>>n>>m;
	n %= m;
	if (!n)
	{
		cout<<0<<endl;
		return ;
	}
	int gd = gcd(n, m);
	int bei = n*m/gd;
	int x1 = bei/n;
	if (x1&(x1-1))
	{
		cout<<-1<<"\n";
		return ;
	}
//	cout<<bei<<endl;
	int avg = bei/m;
	int num = 0;
	while (avg)
	{
		++num;
		avg = (avg&(avg-1));
//		cout<<"avg="<<avg<<endl;
	}
//	cout<<"num="<<num<<endl;
	cout<<num*m-n<<endl;
}

signed main()
{
	int t;
	cin>>t;
	while (t--)
	{
		solve();
	}
	
	
	return 0;
}

Jellyfish and Mex

本题的MEX代表不在数组里面的最小非负整数。每次操作会删除一个数组元素,然后每次会取MEX加到m里面。问最后m可以是多小。

本题直接做得话删除并没有什么规律,也不是每次删最小的就是最优的选择。这个在题目中给的例子就可以看出来。

那么

  1. 如果可以将MEX值的变化找到状态关系,那么就可以使用动态规划求解。
  2. 对于MEX值的状态来说,其实取决于比他大的MEX然后经历了多少次操作。
  3. dp[i] = min(dp[i], dp[j]+(cnt[i]-1)*j+i);
//如果可以将MEX值的变化找到状态关系,那么就可以使用动态规划求解。
//对于MEX值的状态来说,其实取决于比他大的MEX然后经历了多少次操作。
//dp[i] = min(dp[i], dp[j]+(cnt[i]-1)*j+i);
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 5000+10;
int n;
int a[maxn];
map<int, int> cnt;
int dp[maxn];
void solve()
{
	cnt.clear();
	memset(a, 0, sizeof(a));
	int m = 0;
	memset(dp, 127, sizeof dp);
	cin>>n;
	for (int i=0;i<n;i++)
	{
		cin>>a[i];
		m = max(m, a[i]);
		cnt[a[i]]++;
	}
	int pos = 0;
	while (cnt[pos]>=1) pos++;
	if (!pos)
	{
		cout<<"0\n";
		return ;
	}
	dp[pos] = 0;
	int ans = (m+1)*n;
	for (int i=pos-1;i>=0;i--)
	{
		dp[i] = (m+1)*n;
		for (int j=i+1;j<=pos;j++)
		{
//			cout<<"i="<<i<<" dp[i]="<<dp[i]<<endl;
			dp[i] = min(dp[i], dp[j]+(cnt[i]-1)*j+i);
		}
	}
	printf("%lld\n", dp[0]);
}

signed main()
{
	int t;
	cin>>t;
	while (t--)
	{
		solve();
	}
	
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值