P2466 [SDOI2008] Sue 的小球

原题链接

题解

我们发现,当前的决策会影响未来的结果,因此我们把当前的决策存下来,这样等未来要用的时候就有的转移了,如果未来由多个状态决定,那就现在把那些状态都记录下来

我们发现,一个点如果能被吸收,那么其左边或右边的一个区间的点都肯定被吸收了,所以我们记录 f[i][j] 表示区间 [i,j] 的分数,
但是一个区间被遍历完时,最后一个遍历到的点可能在左边或者右边,所以我们再增加一维状态来表示
如果正着计算,那么不仅要存储当前状态的分数,还要存储当前状态的时间,而不同的时间和分数搭配对未来会产生不同的影响,因为分数不是越大越好,时间也不是越短越好,很复杂
不如换个角度来考虑问题,我们令 f[i][j][0/1] 来表示这个区间遍历完时,累积的失去的分数,这样一来,只需要贪心失去的分数越小越好

再有一个疑问:为什么累积扣分最少一定最优?
因为从当前区间向外扩展时扣掉的分数是不会变的,为了使 [1,n] 扣分最少,其前面一个区间扣分也要最少,所以累积扣分最少最优

ps:讲题水平还是不行啊

code

#define ll long long
#include<bits/stdc++.h>
using namespace std;

inline void read(ll &x) {
	x = 0;
	ll flag = 1;
	char c = getchar();
    while(c < '0' || c > '9'){
        if(c == '-')flag = -1;
        c = getchar();
    }
	while(c >= '0' && c <= '9') {
		x = (x << 3) + (x << 1) + (c ^ 48);
		c = getchar();
	}
	x *= flag;
}

inline void write(ll x)
{
    if(x < 0){
    	putchar('-');
		x = -x;
	}
    if(x > 9)
		write(x / 10);
    putchar(x % 10 + '0');
}

ll n,x0;
struct unit
{
    ll x,y,v;
}ball[1005];
bool cmp(unit a,unit b)
{
    return a.x<b.x;
}

ll pres[1005]={0};
ll dp[1005][1005][2]={0};
int main()
{
    read(n); read(x0);

    ball[n+1].x=x0;//很机智的一个做法:把初始点加进去,y和v都为0,相当于出发点

    ll sum=0;
    for(ll i=1;i<=n;i++) read(ball[i].x);
    for(ll i=1;i<=n;i++) read(ball[i].y),sum+=ball[i].y;
    for(ll i=1;i<=n;i++) read(ball[i].v);

    n++;//注意
    sort(ball+1,ball+n+1,cmp);

    for(ll i=1;i<=n;i++) pres[i]=pres[i-1]+ball[i].v;

    memset(dp,0x3f,sizeof dp);
    ll i;
    for(i=1;i<=n;i++)
        if(ball[i].x==x0)
        {
            dp[i][i][0]=dp[i][i][1]=0;
            break;
        }
    for(ll len=2;len<=n;len++)
    {
        for(ll l=1,r=len;r<=n;l++,r++)
        {
            dp[l][r][0]=min(dp[l+1][r][0]+(ball[l+1].x-ball[l].x)*(pres[n]-pres[r]+pres[l]),dp[l+1][r][1]+(ball[r].x-ball[l].x)*(pres[n]-pres[r]+pres[l]));
            dp[l][r][1]=min(dp[l][r-1][0]+(ball[r].x-ball[l].x)*(pres[n]-pres[r-1]+pres[l-1]),dp[l][r-1][1]+(ball[r].x-ball[r-1].x)*(pres[n]-pres[r-1]+pres[l-1]));
            //思维反转,不计算这么走能得到的分数,而是计算这么走会失去多少分数
        }
    }

    printf("%.3lf",(sum-min(dp[1][n][0],dp[1][n][1]))*1.0/1000);
    return 0;
}

posted @   纯粹的  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示