[ CodeVS冲杯之路 ] P1098

   不充钱,你怎么AC?

     题目:http://codevs.cn/problem/1098/

 

     显然就是使每堆牌达到总体的平均数,尽量使每次移动时的牌数最大,这就类似于飞行棋,将几个棋子叠起来一起走是最优的。

     我们将数组变为关于平均数的浮动,然后每次寻找距离最小的一正一负的两个位置,将绝对值小的补上,也就是将其中一个变为0(若绝对值相等就是两个),再从多的往少的一个个标记,代表会往那边移动一次。注意这里要开一个左一个右,因为向左和向右是代表的两种不同得方案。那么这样我们就达到了每次移动牌数尽可能最多。可能思路讲的不是很清晰,具体请参考代码。

 

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 #define N 110
 8 using namespace std;
 9 
10 struct data
11 {
12     int l,r;
13 }
14     f[N];
15 int a[N];
16 int main()
17 {
18     int i,n,k,sum,l,r;
19     scanf("%d",&n);
20     sum=0;
21     for (i=1;i<=n;i++)
22         {
23             scanf("%d",&a[i]);
24             sum+=a[i];
25             f[i].l=f[i].r=0;
26         }
27     sum/=n;
28     for (i=1;i<=n;i++) a[i]-=sum;
29     l=r=1;
30     while (1)
31         {
32             while (a[l]>=0&&l<=n) l++;
33             while (a[r]<=0&&r<=n) r++;
34             if (r>n||l>n) break;
35             k=min(-a[l],a[r]);
36             a[l]+=k;
37             a[r]-=k;
38             if (r>l) for (i=r;i>l;i--) f[i].l=1;
39             else for (i=r;i<l;i++) f[i].r=1;
40         }
41     sum=0;
42     for (i=1;i<=n;i++) sum+=f[i].l+f[i].r;
43     printf("%d\n",sum);
44     return 0;
45 }

 

posted @ 2016-09-11 10:14  Hadilo  阅读(218)  评论(0编辑  收藏  举报