[ 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 }