bzoj5311 贞鱼 codeforces321ECiel and Gondolas wqs二分+决策单调性优化

本文详细解析了Codeforces第321场E题的解题思路与代码实现,采用预处理和动态规划方法,优化读入和处理速度,最终解决了一道看似复杂的卡常数题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门: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;
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值