[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代码:
见董晓