第200个AC。
最大值最小化的问题。可以用DP也可用二分做。
dp[i][j]表示从j个数字中切i次所得的最小的最大值。
dp[i][j]=min{max(dp[i-1][k],s[k-j])} s[k-j]表示k到j的和 其中 1<=k<j
一开始以为k的范围是i+1到j,这里WA了一次。
DP:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define INF 0x7f7f7f7f
using namespace std;
int dp[305][605];
int a[605];
int sum[605];
int main()
{
int N,K;
while(scanf("%d%d",&N,&K)!=EOF)
{
memset(dp,0,sizeof(dp));
memset(a,0,sizeof(a));
memset(sum,0,sizeof(sum));
for(int i=1; i<=N+1; ++i)
{
scanf("%d",&a[i]);
dp[0][i]=sum[i]=sum[i-1]+a[i];
}
for(int i=1; i<=K; ++i)
for(int j=1; j<=N+1; ++j)
{
int mn=INF;
for(int k=1; k<=j; ++k)
mn=min(mn,max(dp[i-1][k],sum[j]-sum[k]));
dp[i][j]=mn;
}
printf("%d\n",dp[K][N+1]);
}
return 0;
}
速度更快一些的二分法:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define INF 0x7f7f7f7f
using namespace std;
int N,K;
int a[605];
bool Judge(int val)
{
int sum=0,n=0;
for(int i=1; i<=N+1; ++i)
{
if(a[i]>val) return false;
else
{
if(sum+a[i]<=val)
sum+=a[i];
else
{
n++;
sum=a[i];
}
}
}
if(sum<=val) n++;
if(n-1>K) return false;
else return true;
}
int Bsearch(int low,int high)
{
int mid;
while(low<high)
{
mid=(low+high)/2;
if(Judge(mid)) high=mid;
else low=mid+1;
}
return low;
}
int main()
{
while(scanf("%d%d",&N,&K)!=EOF)
{
memset(a,0,sizeof(a));
int sum=0;
for(int i=1; i<=N+1; ++i)
{
scanf("%d",&a[i]);
sum+=a[i];
}
int ans=Bsearch(0,sum);
printf("%d\n",ans);
}
return 0;
}