传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=5311 竟然照搬cf原题。。。
http://codeforces.com/problemset/problem/321/E 原来div1 E题也有简单题。。。
究极卡常题,加了fread还跑了2600ms,O(nlogVlogn)的复杂度比读入和预处理还低,估计大部分时间都花在读入和预处理上了
基本思路和https://blog.youkuaiyun.com/liufengwei1/article/details/98475702 一模一样
就是计算代价他这里n^2全部输入了需要预处理,而之前那题只输入了n个是需要推出公式
#include<bits/stdc++.h>
#define maxl 4010
using namespace std;
int n,k,ans;
int sum[maxl][maxl],w[maxl][maxl];
int dp[maxl],num[maxl],q[maxl],nxt[maxl];
namespace fastIO
{
#define BUF_SIZE 100000
bool IOerror = 0;
inline char nc()
{
static char buf[BUF_SIZE];
static char *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
if(p1 == pend)
{
p1 = buf;
pend = buf + fread(buf, 1, BUF_SIZE, stdin);
if(pend == p1)
{
IOerror = 1;
return -1;
}
}
return *p1++;
}
inline bool blank(char ch) {
return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
}
inline int rd(int &x)
{
char ch;
while(blank(ch = nc()));
if(IOerror) return -1;
for(x=ch-'0';(ch=nc())>='0' && ch<='9';x=x*10+ch-'0');
return 1;
}
#undef BUF_SIZE
};
using namespace fastIO;
inline void prework()
{
for(register int i=1;i<=n;++i)
for(register int j=1;j<=n;++j)
{
//scanf("%d",&sum[i][j]);
rd(sum[i][j]);
sum[i][j]+=sum[i][j-1];
}
for(register int i=1;i<=n;++i)
{
w[i][i]=0;
for(int j=i+1;j<=n;j++)
w[i][j]=w[i][j-1]+sum[j][j]-sum[j][i-1];
}
}
inline bool cmp(int i,int j,int nxt)
{
int val1=dp[i]+w[i+1][nxt];
int val2=dp[j]+w[j+1][nxt];
if(val1==val2)
return num[i]<num[j];
return val1<val2;
}
inline int jug(int val)
{
int head=1,tail=1,l,r,mid;
q[1]=0;nxt[1]=1;num[0]=0;
for(register int i=1;i<=n;++i)
{
while(head<tail && nxt[head+1]<=i)
head++;
dp[i]=dp[q[head]]+w[q[head]+1][i]+val;
num[i]=num[q[head]]+1;
while(head<=tail && i<nxt[tail] && cmp(i,q[tail],nxt[tail]))
tail--;
l=nxt[tail];r=n+1;
while(l+1<r)
{
mid=(l+r)>>1;
if(cmp(i,q[tail],mid))
r=mid;
else
l=mid;
}
if(cmp(i,q[tail],l))
l=l;
else
l=l+1;
if(l<=n)
q[++tail]=i,nxt[tail]=l;
}
return num[n];
}
inline void mainwork()
{
int l=0,r=w[1][n]+1,mid;
while(l+1<r)
{
mid=(l+r)>>1;
if(jug(mid)<=k)
r=mid;
else
l=mid;
}
if(jug(l)<=k)
ans=dp[n]-l*k;
else
if(jug(l+1)<=k)
ans=dp[n]-(l+1)*k;
}
inline void print()
{
printf("%d\n",ans);
}
int main()
{
while(~rd(n))
{
rd(k);
prework();
mainwork();
print();
}
return 0;
}