[NOIP2002 提高组]均分

P1031 [NOIP2002 提高组] 均分纸牌 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

贪心思想:从前往后遍历,每次都将遍历到的纸牌堆调整到目标值。

AC代码:

模拟出规律,重在”短视、每一次完成“。本题:”多退少补“

#include<iostream>
#include<algorithm>
using namespace std;
int n, ave, a[110], cnt;
int main(){
	cin>>n;
	for(int i = 1; i<=n; i++){
		cin>>a[i];
		ave += a[i];
	}
	ave /= n;
	//每次操作成负数也无所谓 
	for(int i = 1; i<=n; i++){
		if(a[i] - ave){
			a[i+1] += a[i] - ave;//多退少补 
			cnt ++ ;
		}
	}
	cout<<cnt;
	return 0;
}

原来想法:每次处理数量最大的堆,用大根堆存储。这样的想法不够短视:每次贪心都可以作为当下条件的最佳情况。不要返工。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N = 10010;
int n, a[N], cnt;
LL sum;
int main(){
	cin>>n;
	priority_queue<PII> q;
	for(int i = 1; i<=n; i++){
		cin>>a[i];
		sum += a[i];
		q.push({a[i], i}); //值、下标 
	}
	int s = sum / n;
	while(q.size()){
		auto t = q.top();
		q.pop();
		int x;
		//这一块具体操作的逻辑混乱 
		int va = t.first, ve = t.second;
		if(a[ve-1]>s && a[ve+1]>s) continue;
		if(a[ve-1]>a[ve+1]) x = s - a[ve+1], a[ve+1] += x;
		else x = s - a[ve-1], a[ve-1] += x;
		a[ve] -= x; 
		cnt ++ ;
	}
	cout<<--cnt;
	return 0;
}

P2512 [HAOI2008] 糖果传递

朴素做法,破环成链,可用传递纸牌的想法,但是时间复杂度过高

经过数学推导,与‘货仓选址“类似

TLE代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue> 
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N = 10010;
int n;
LL a[N], cnt, sum;
int main(){
	scanf("%d", &n);
	priority_queue<PII> q;
	for(int i = 1; i<=n; i++){
		scanf("%lld", &a[i]);
		sum += a[i];
		q.push({a[i], i}); //值、下标 
	}
	int s = sum / n;
	while(q.size()){
		auto t = q.top();
		q.pop();
		int x = 0;
		int va = t.first, ve = t.second;
		if(a[ve] == s) continue;
		int l = ve-1, r = ve+1;
		if(ve==1) l = n;
		if(ve==n) r = 1;
		if(a[l]>s && a[r]>s) continue;
		if(a[l]>a[r]) x = s - a[r], a[r] += x;
		else x = s - a[l], a[l] += x;
		a[ve] -= x; 
		cnt += x;
		if(a[ve]!=s) q.push({a[ve], ve});
		//cout<<cnt<<' ';
	}
	//puts("");
	printf("%lld", cnt);
	return 0;
}

AC代码:

见董晓