七夕祭(类似于糖果传递)

原题
思路:这道题目思路和糖果传递思路类似,下面写出糖果传递题目糖果传递

有n个小朋友坐成一圈,每人有a[i]个糖果。

每人只能给左右两人传递糖果。

每人每次传递一个糖果代价为1。

求使所有人获得均等糖果的最小代价。
输入格式

第一行输入一个正整数n,表示小朋友的个数。

接下来n行,每行一个整数a[i],表示第i个小朋友初始得到的糖果的颗数。
输出格式

输出一个整数,表示最小代价。
数据范围

1≤n≤1000000


数据保证一定有解。
输入样例:

4
1
2
5
4

输出样例:

4

思路:
1.分析题意

1->2->3->4->...->n->1  构成一个环
 x1 x2 x3 x4 .... xn   xi表示xi给xi+1糖果的个数,xi可正可负可为零。
 本题要求|x1|+|x2|+|x3|+.....+|xn|的最小值。

 限制条件:最后每个人获得均等糖果。
 av表示平均值,a数组表示每个人初始糖果的数量。

2.列出式子

Xn - X1 + a1 = avg
x1 - x2 + a2 = avg
....
Xn-1 - Xn + an = avg

3.推导出

x2 = x1 - (avg - a2)
x3 = x2 -(avg - a3)
.....
xn = Xn-1 - (avg - an)

4.规律

x2 = x1 - c2      (c2 = c1  + avg -a2)
x3 = x1 - c3      (c3 = c2 + avg - a3)
...
xn = Xn-1 - cn    (cn = Cn-1 + avg - an)

5.问题转化

|x1 - c1| + |x2 - c2| +...+|xn - cn|  
转化为货仓选址问题
结论 :我们首先把所有坐标排个序然后找出中位数即可如果是奇数
个,那中位数就是最中间的。如果是偶数个,那中位数在最中间的两
个之间,取这两个的任意一个都是答案(因为是整形嘛)

货仓选址

6.糖果传递代码

#include<iostream>
#include<algorithm>
#include<cmath>

const int N = 1e6 + 10;
int a[N];
int c[N];
int n;
using namespace std;

int main()
{
	
	int i = 0;
	long long sum = 0;
	cin>>n;
	for(i = 1;i <= n;i++)
	{
		scanf("%d",&a[i]);
		sum += a[i];
		
	}
	
	int avg = sum/n;
	
	for(i = 2;i <= n;i++)
	{
		c[i] = c[i-1] + avg -a[i];
	}
	
	sort(c+1,c+n+1);
	long long coun = 0;
	int k = 1 + n >>1;
	for(i = 1;i <= n;i++)
	{
		coun += abs(c[k] - c[i]);
	}
	
	cout<<coun<<endl;
	return 0;
}

7.七夕祭代码

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
int n,m,t;
int x[N];
int y[N];
int row[N];
int column[N];
long long c[N];

int main()
{
	
	cin>>n>>m>>t;
	for(int i = 1;i <= t;i++)
	{
		scanf("%d",&x[i]);
		scanf("%d",&y[i]);
		row[x[i]]++;
		column[y[i]]++;
			
	}
	
	if((t % n !=0) && (t % m != 0))
	{
		printf("impossible\n");
	}
	else if(t % n != 0)
	{
		int avg = t/m;
		for(int i = 2;i<=m;i++)
		{
			
			c[i] = c[i-1] + avg -column[i];
		
		}
		
		sort(c+1,c+m+1);
		long long coun = 0;
		int k = 1 + m >>1;
		for(int i = 1;i <= m;i++)
		{
			coun += abs(c[k] - c[i]);
		}
	
		cout<<"column "<<coun<<endl;
	}
	else if(t %m != 0)
	{
		int avg = t/n;
		for(int i = 2;i<=n;i++)
		{
			
			c[i] = c[i-1] + avg -row[i];
		
		}
		
		sort(c+1,c+n+1);
		long long coun = 0;
		int k = 1 + n >>1;
		for(int i = 1;i <= n;i++)
		{
			coun += abs(c[k] - c[i]);
		}
	
		cout<<"row "<<coun<<endl;
	}
	else
	{
		
		int avg = t/m;
		for(int i = 2;i<=m;i++)
		{
			
			c[i] = c[i-1] + avg -column[i];
		
		}
		
		sort(c+1,c+m+1);
		long long coun1 = 0;
		int k = 1 + m >>1;
		for(int i = 1;i <= m;i++)
		{
			coun1 += abs(c[k] - c[i]);
		}
	
		for(int i = 1;i<=m;i++)
		{
			c[i] = 0;
		}
		
		avg = t/n;
		for(int i = 2;i<=n;i++)
		{
			
			c[i] = c[i-1] + avg -row[i];
		
		}
		
		sort(c+1,c+n+1);
		long long coun2 = 0;
		k = 1 + n >>1;
		for(int i = 1;i <= n;i++)
		{
			coun1 += abs(c[k] - c[i]);
		}
		long long coun = coun1 + coun2;
		cout<<"both "<<coun<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值