Picnic Cows
Time Limit: 8000/4000 MS(Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2880 Accepted Submission(s): 910
Problem Description
It’s summer vocation now.After tedious milking, cows are tired and wish to take a holiday. So FarmerCarolina considers having a picnic beside the river. But there is a problem,not all the cows consider it’s a good
idea! Some cows like to swim in West Lake,some prefer to have a dinner in Shangri-la ,and others want to do somethingdifferent. But in order to manage expediently, Carolina coerces all cows tohave a picnic!
Farmer Carolina takes her N (1<N≤400000) cows to the destination, but shefinds every cow’s degree of interest in this activity is so different that theyall loss their interests. So she has to group them to different teams to makesure that every cow can go to
a satisfied team. Considering about the security,she demands that there must be no less than T(1<T≤N)cows in every team. Asevery cow has its own interest degree of this picnic, we measure this interestdegree’s unit as “Moo~”. Cows in the same team should reduce
their Moo~ to theone who has the lowest Moo~ in this team——It’s not a democratical action! SoCarolina wishes to minimize the TOTAL reduced Moo~s and groups N cows intoseveral teams.
For example, Carolina has 7 cows to picnic and their Moo~ are ‘8 5 6 2 1 7 6’and at least 3 cows in every team. So the best solution is that cow No.2,4,5 ina team (reduce (2-1)+(5-1) Moo~)and cow No.1,3,6,7 in a team (reduce((7-6)+(8-6)) Moo~),the answer is
8.
Input
The input contains multiplecases.
For each test case, the first line has two integer N, T indicates the number ofcows and amount of Safe-base line.
Following n numbers, describe the Moo~ of N cows , 1st is cow 1 , 2nd is cow 2,and so on.
Output
One line for each test case,containing one integer means the minimum of the TOTAL reduced Moo~s to group Ncows to several teams.
Sample Input
7 3
8 5 6 2 1 7 6
Sample Output
8
题意:给出n个数,要求把这些数分成若干组,每组至少有t个数,每组的reduce值为该组所有数依次减去这组最小的那个数的和,求所有组reduce值和的最小值
分析:肯定是要把小的数放在一起,大的数放在一起,故先对这些数进行排序
然后写出状态转移方程:dp[i]= min{dp[j]+(sum[i]-sum[j])-a[j+1](i-j)} 其中dp[i]表示前i个数分隔后得到的最小值
假设k<=j<i-t,j+1~i作为一组比以k+1~i作为一组更优
则dp[j]+sum[i]-sum[j]-(i-j)*a[j+1] <= dp[k]+sum[i]-sum[k]-(i-k)*a[k+1]
=>dp[j]+sum[i]-sum[j]+j*a[j+1]-i*a[j+1] <= dp[k]+sum[i]-sum[k]+k*a[k+1]-i*a[k+1]
=>(dp[j]-sum[j]+j*a[j+1] - (dp[k]-sum[k]+k*a[k+1]))/(a[j+1]-a[k+1])<=i
令yj=dp[j]-sum[j]+j*a[j+1],yk=dp[k]-sum[k]+k*a[k+1]); xj=a[j+1], xk=a[k+1];
则表达式变为(yj-yk)/(xj-xk)<=i;左边为斜率的表示,维护斜率即可
#include <bits/stdc++.h>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define f(i,a,b) for(int i=(a);i<=(b);++i)
const int maxn = 400005;
const int mod = 9973;
const int INF = 0x3f3f3f3f;
const double eps = 1e-6;
#define ll long long
#define rush() int T;scanf("%d",&T);while(T--)
int q[maxn];
ll a[maxn],sum[maxn];
ll dp[maxn];
ll getdp(int i,int j)
{
return dp[j]+(sum[i]-sum[j])-a[j+1]*(i-j);
}
ll getup(int j,int k)
{
return dp[j]-sum[j]+j*a[j+1]-(dp[k]-sum[k]+k*a[k+1]);
}
ll getdown(int j,int k)
{
return a[j+1]-a[k+1];
}
int main()
{
int n,t;
int head,tail;
while(~scanf("%d%d",&n,&t))
{
for(int i=1;i<=n;i++)
{
scanf("%I64d",&a[i]);
}
sort(a+1,a+n+1);
sum[0]=dp[0]=0;
for(int i=1;i<=n;i++)
{
sum[i]=sum[i-1]+a[i];
}
head=tail=0;
q[tail++]=0;
for(int i=1;i<=n;i++)
{
while(head+1<tail&&getup(q[head+1],q[head])<=i*getdown(q[head+1],q[head]))
head++;
dp[i]=getdp(i,q[head]);
int cnt=i-t+1;
if(cnt<t)
continue;
while(head+1<tail&&getup(cnt,q[tail-1])*getdown(q[tail-1],q[tail-2])<=getup(q[tail-1],q[tail-2])*getdown(cnt,q[tail-1]))
tail--;
q[tail++]=cnt;
}
printf("%I64d\n",dp[n]);
}
return 0;
}