傳送門:BZOJ1044
第一問:傻逼二分,設答案爲ans,二分貪心即可。
第二問:
轉移是
顯然這個Dp空間是
首先,我們可以預處理對於每個j,k的最小值,因爲j,k都是不嚴格單調的,這一步可以在線性的時間內完成
至於空間,顯然可以滾動。
AC之後的吐槽。
你個xxxxx,把傻逼二分寫錯了調了半天是吧!
g數組不能取模,即使取模也只能用經典的減法意義下的取模!
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int p=10007;
int n,m;
int da[50005];
int sum[50005];
int pre[50005];
int ans,num;
int f[3][50005];
int g[50005];
bool can(int ans)
{
int num=0,jec=0;
for(int i=1;i<=n;i++){
if(num+da[i]<=ans)
num+=da[i];
else
if(da[i]>ans)
return false;
else
jec++,num=da[i];
}
return jec<=m;
}
int Middle()
{
int a=1,b=100000005;
while(a<b){
int mid=(a+b)/2;
if(can(mid))
b=mid;
else
a=mid+1;
}
return a;
}
void First()
{
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+da[i];
ans=Middle();
int j=1;
for(int i=1;i<=n;i++){
while(sum[i]-sum[j]>ans)
j++;
pre[i]=j-1;
}
}
void Solve()
{
for(int i=1;i<=n;i++)
if(sum[i]<=ans)
f[1][i]=1;
else
break;
int o=0;
for(int i=n-1;i>=1;i--)
if(sum[n]-sum[i]>ans)
break;
else{
num+=f[o^1][i];
num%=p;
}
for(int i=2;i<=m;i++){
for(int j=1;j<=n;j++){
g[j]=g[j-1]+f[o^1][j];
//g[j]%=p;
}
for(int j=1;j<=n;j++){
f[o][j]=g[j-1]-g[pre[j]];
f[o][j]%=p;
}
for(int j=n-1;j>=1;j--)
if(sum[n]-sum[j]>ans)
break;
else{
num+=f[o][j];
num%=p;
}
o^=1;
}
/*for(int i=1;i<=n;i++)
printf("%d\n",f[o^1][i]);*/
printf("%d %d",ans,num);
}
void Readdata()
{
freopen("loli.in","r",stdin);
//freopen("loli.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&da[i]);
}
void Close()
{
fclose(stdin);
fclose(stdout);
}
int main()
{
Readdata();
First();
Solve();
Close();
return 0;
}