2 条题解
-
19
P1731. [NOIP2002 提高组] 均分纸牌 题解
涉及算法:贪心,模拟
第一步,看题,有题目可知,纸牌的总数一定是的倍数,那这一条件就为我们后面的贪心奠定了基础。
第二步,想思路,如果就参照普通的思路将比平均值多的移到少的上面,那显然这不是最少需要的步骤,就拿样例举例:
输入样例:9 8 17 6
这组样例的平均值是:10,缺了1,缺了3,多了7,少了4
如果按照我们原来的把多的移到少的上去的思路,那么把缺了的1补上就要从上移1到这上面,这样就需要2步,再从上移2到上,这样有需要1步,同理,从移4到上,又需要1步
总的步数是:,显然,这与样例不符,那要如何做呢?
而我们的贪心策略,也就根据普通做法而产生了
如果我们把所有的数都减去平均值,那么整个样例就会变成:-1 -2 7 -4,不难发现,负数表示当前纸牌缺了多少,正数表示当前纸牌多了多少,那么我们只需要让所有数都向0靠拢,也就是我们修改后的样例全部向右移动
这样的操作进行一次样例将变成:0 -3 7 -4,第二次:0 0 4 -4,第三次:0 0 0 0,这样算下来就是三步
第三步,代码实现:
1、算平均值:
- 这个操作很简单,只需要边输入边求和,最后再把求和的结果除以纸牌的就可以
2、贪心的实现
- 这个操作的做一下预处理(我喜欢这么叫,具体是不是,得看大家怎么认为),预处理怎么做呢?其实就是思路中的所有的数据都减去平均值
- 接下来就是真正的贪心了,如果,那直接跳过,说明这里的纸牌已经不用修改了,否则就让加上,这样的加就相当与一次移动了,所以有关总的移动次数就要+1
3、输出答案
- 这没什么好讲的吧,也就是输出对应的移动次数而已
讲解就到这了,下面上对标的程序
对标代码实现1的代码(标程①):
// 计算平均值 for (re i = 1; i <= n; i++) { cin >> a[i]; sum += a[i]; // 累加求和 } avg = sum / n; // avg就是酸的的平均值
对标代码实现2的代码(标程②):
for (re i = 1; i <= n; i++) a[i] -= avg; // 减去平均值,思路中有详细介绍其作用 // 下面是贪心 for (re i = 1; i < n; i++) { if (a[i] == 0) continue; // 如果a[i]是0,那不用做任何改动,直接跳过即可,不用计入总的步数 a[i + 1] += a[i]; // 向右靠拢 a[i] = 0; // 将当前的纸牌赋值为0,应为当前纸牌缺少的或是多出的已经移到了下一张纸牌上了 ans++; // 将需要的步数的计数器加1,表示需要移一步 }
对标代码实现3的代码(标程③):
cout << ans << endl; // 输出答案
#include <bits/stdc++.h> #define ll long long #define re register int using namespace std; ll n, a[105], avg, sum, ans; // n表示纸牌总数,a表示纸牌,avg表示平均值,sum表示总和,ans表示一共需要的移动次数 int main() { ios::sync_with_stdio(false); // 读入加速 cin.tie(0); cout.tie(0); cin >> n; /* 这里我就不放代码了,只要把标程全部复制下来就可以了 */ return 0; }
算了,还是上完整代码吧!
#include <bits/stdc++.h> #define ll long long #define re register int using namespace std; ll n, a[105], avg, sum, ans; int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> n; for (re i = 1; i <= n; i++) { cin >> a[i]; sum += a[i]; } avg = sum / n; for (re i = 1; i <= n; i++) a[i] -= avg; for (re i = 1; i < n; i++) { if (a[i] == 0) continue; a[i + 1] += a[i]; a[i] = 0; ans++; } cout << ans << endl; return 0; }
代码很短吧,说起来麻烦,其实做起来很简单
End,撒花~~~
-
5
#include <bits/stdc++.h> using namespace std; int main() { int avg=0, n, a[101], i, tot=0, j; cin>>n; for(i=0;i<n;i++) { cin>>a[i]; avg+=a[i]; } avg/=i; for(j=0;j<n;j++) a[j]-=avg; i=0;j=n-1; while(a[i]==0&&i<n) i++; while(a[j]==0&&j>1) j--; for(int t=i;t<j;t++) { if(a[t]==0) continue; a[t+1]+=a[t]; a[t]=0; tot++; } cout<<tot; return 0; }
- 1
信息
- ID
- 1731
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 2
- 标签
- 递交数
- 123
- 已通过
- 77
- 上传者