HDU-6237 A Simple Stone Game(思维+贪心)

传送门

Problem Description
After he has learned how to play Nim game, Bob begins to try another stone game which seems much easier.

The game goes like this: one player starts the game with N piles of stones. There is ai stones on the ith pile. On one turn, the player can move exactly one stone from one pile to another pile. After one turn, if there exits a number x(x>1) such that for each pile bi is the multiple of x where bi is the number of stone of the this pile now), the game will stop. Now you need to help Bob to calculate the minimum turns he need to stop this boring game. You can regard that 0 is the multiple of any positive number.

Input
The first line is the number of test cases. For each test case, the first line contains one positive number N(1≤N≤100000), indicating the number of piles of stones.

The second line contains N positive number, the ith number ai(1≤ai≤100000) indicating the number of stones of the ith pile.

The sum of N of all test cases is not exceed 5∗105.

Output
For each test case, output a integer donating the answer as described above. If there exist a satisfied number x initially, you just need to output 0. It’s guaranteed that there exists at least one solution.

Sample Input
2
5
1 2 3 4 5
2
5 7

Sample Output
2
1

题意:每次可以从一堆石子拿走一个石子放在另一堆上,问最少多少次操作以后各堆的石子数有大于1得一个公因数。



思路:刚开始的思路是对的,就是对石子数之和分解质因数,最后各堆到达的石子数一定是总和的一个质因数,然后求到达每个质因数对应的最小次数,取min即可。然鹅我求次数的时候出了问题,正解应该是:取最小次数的时候得使用贪心思想,即把每个数%完质因数的值从大到小排序,依次把它们补满,直到互补为止。


题外:
,,我在求次数的时候想的是,如果最后到达的数是x,那么每个数%完x的数,要么把它去掉,要么把它补到x,我直接对于每一堆取最优解,即取min(a[i]%x, x-a[i]%x),加起来一定是答案,,,我证明不了它是错的,但是我就感觉是对的,,还试了几个样例,也没试出错来,然鹅,它就是错的,啪啪打脸…现在也还没想出来它为啥是错的
评测姬:我不要你觉得,我要我觉得(冷酷脸)

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll; 
const int N = 1e5+10,inf=1e18;
ll a[N],prime[N],b[N];
int n,cnt;
bool isprime[N];
bool cmp(int x,int y)
{
	return x>y;
}
ll cal(ll x)
{
	ll ans=0,sum=0;
	int num=0;
	for(int i=0;i<n;i++)
	{
		sum+=a[i]%x;   
		if(a[i]%x)
			b[num++]=a[i]%x;
	}
	sort(b,b+num,cmp);
	for(int i=0;i<num;i++)
	{
		if(sum<=0) break;
		ans+=x-b[i];sum-=x;//这个sum一定是x的倍数,所以可以直接每次凑出一个x就减掉一个
	}
	return ans;
}
void init()
{
	for(ll i=2;i<N-5;i++)
	{
		if(!isprime[i])
		{
			prime[cnt++]=i;
			for(ll j=i+i;j<N-5;j+=i)
				isprime[j]=true;
		}
	}
}
int main()
{
	init();  //素数筛
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		ll sum=0;
		ll ans=inf;
		for(int i=0;i<n;i++)
			scanf("%lld",&a[i]),sum+=a[i];	
		sort(a,a+n);	
		for(int i=0;prime[i]<=sum/prime[i]&&i<cnt;i++)
		{
			ll x=prime[i];
			if(sum%x==0)
				ans=min(ans,cal(x)),ans=min(ans,cal(sum/x));
		}
		if(ans==inf)  //如果sum是个质数,那么最后只能把所有石子合并成一堆
			ans=sum-a[n-1];
		printf("%lld\n",ans);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值