Problem
Description
Input
Output
Sample Input
6 6
1 2
1 3
2 4
2 5
4 6
5 6
Sample Output
3
4 5 6
Data Constraint
Solution
除了求最小费用,还有一种方法(贪心)。
我们破环为链,枚举起点与终点,运钱只能最多运到重点。
首先保证起点合法。
设起点为i,合法条件为:
Σk=jk=i≥cnt——(i<j≤终点)
cnt表示i~j钱仓的个数。因为如果钱仓个数大于钱数,无论你怎么向前移,后面的钱仓都没有多余的钱补给。
保证起点合法之后,如果
ci>1
,那么我们就要将
ci−1
的钱向前补。
现在证明这为什么是最优解。如果同样的钱,假设从i移到j要走a步,从j移到k要走b步,所以从i移到k就要花费
(a+b)2=a2+b2+2ab
。而如果将j移到k,然后将i移到j,就花费
a2+b2
,少花费2ab。
所以我们枚举起点,取最小答案就行了。
Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define N 200010
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
int c[N],b[N],i,j,k,l,n,m,t,wz;
long long ans,sum;
long long ff(int n) {return n*(n+1)*(2*n+1)/6;}
int main()
{
scanf("%d",&n);
fo(i,1,n)
{
scanf("%d",&c[i]);
c[n+i]=c[i];
b[i]=b[i-1]+c[i];
}
fo(i,n+1,n*2) b[i]=b[i-1]+c[i];
ans=100000000000000000;
fo(i,1,n)
{
bool p=0;
fo(j,i,i+n-1)
if (b[j]-b[i-1]<j-i+1)
{
p=1;
break;
}
if (!p)
{
sum=0;
wz=i-1;
fo(j,i,i+n-1)
{
wz+=c[j];
sum+=ff(wz-j)-ff(max(0,wz-j-c[j]));
}
ans=min(ans,sum);
}
}
printf("%lld",ans);
}
——2016.8.11