均衡操作

 

小J面前有N桶水,每个桶装的水的体积不一样

现在小J希望让所有桶的水的体积变得一样

每次他会选择两个相邻的桶子,将一个桶的水倒入另一个桶,然后将空桶丢掉。

问他至少操作多少次,使得所有桶的水一样多。

Format
Input
第一行给出数字T,代表数据的组数

对于每组数据,先给出N

下面一行给出N个数字,代表每个桶的水的体积

N<=1e5

T<=10

所有数字之和<=1e6

Output
如题

Samples
输入数据 1
1
6
1 2 3 1 1 1
输出数据 1
3
Hint

第1次,小J将第1个与第2个桶合并,得到数列(3,3,1,1,1)

第2次,小J将第4个与第5个桶合并,得到数列(3,3,1,2)

第2次,小J将第3个与第4个桶合并,得到数列(3,3,3)

 

 

Sol:

每个水桶开始的体积知道了,于是总体积sum也就知道了。

发现每次合并就减少一个桶,于是如果知道最终还有多少个桶,就知道了合并了几次

于是我们逆序枚举一下,最终还有多少个桶,设之为i

于是每个桶最终的体积为sum/i,自然sum%i必须为0

接下来,我们就来检查一下,合并的过程中是否有出错

由于在合并时,是不断将小数字合并成一个大数字,于是如果发现合并后的体积,或者某个水桶目前的体积是大于sum/i的,则合并是出错的。

例如

4个桶

1 2 3 6

于是sum=1+2+3+6=12

假设i=3,于是sum/i=12/3=4

于是我们从左扫到右

就会发现1+2+3=6>4

于是合并失败

 

再让i=2,sum/i=12/2=6

发现合并的过程是不会出错的。

于是合并的次数就等于 N-i=4-2=2

 

总结:

这个题还是比较简单的,有多种枚举方式,例如枚举最终每个桶的水的体积是多少。

当然这个体积也必须是总体积sum的约数才行。

 

 

方法1:枚举最终留下多少个桶

#include<bits/stdc++.h>
using namespace std;
int a[1000006];
int main() {
  int T;
  cin >> T;
  while (T--) 
  {
    int n;
    cin >> n;
    int sum = 0;
    for (int i = 0; i < n; i++) 
	{
      cin >> a[i];
      sum += a[i];
    }
    int ans;
    for (int i = n; i >= 1; i--) 
    //最后剩下多少堆 
	{ 
          if (sum % i != 0)
              continue;
          int cur = 0;
          bool flag = 1;
          for (int j = 0; j < n; j++) 
	      {
                   cur += a[j];
                   if (cur > sum / i) 
		           {
                        flag = 0;
                        break;
                   } 
		          else if (cur == sum / i) 
		          {
                          cur = 0;
                  }
         }
      if (flag) 
	  {
        ans = n - i;
        break;
      }
    }
    cout << ans << endl;
  }
  return 0;
}

  

 方法2:枚举体积

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int t,n,s,cnt,a[maxn],p[1005],res,ans;
bool flag;
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		flag=ans=cnt=s=0;
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			flag|=(a[i]!=a[1]);
			s+=a[i];
		}
		if(!flag)
		{
			printf("0\n");	continue;
		}
		for(int i=1;i<=s;i++)
		{
			if(s%i)
				continue;
			p[++cnt]=i;
		}
		for(int i=1;i<=cnt;i++)
		//枚举每个桶里有多少水,从小到大枚举,找到第一个解就退出 
		{
			res=ans=0;
			bool ok=true;
			for(int j=1;j<=n;j++)
			{
				res+=a[j];
				ans++;
				if(res==p[i])
				{
					res=0;
					ans--;
				}
				if(res>p[i])
				{
				     ok=false;
					 break;	
			    }
			
	    	}
	      	if (ok==true)
	    	{
	    	
    		     printf("%d\n",ans);
    		     break;
	        }
	    }
    }
	return 0;
}

  

posted @ 2022-09-10 15:49  我微笑不代表我快乐  阅读(49)  评论(0编辑  收藏  举报