zoukankan      html  css  js  c++  java
  • bzoj2037 Sue的小球(区间dp,考虑到对未来的贡献)

    ​​​​​​​​​​​​​​大致意思就是现在你要不断的奔跑到不同的地点去接球,每一秒可以移动一个单位长度,而你接到一个球的动作是瞬间的,收益是y[i]-t*v[i] 然后呢,要求分数最高。

    起初看这个题目QWQ完全没有任何思路,大概只能想到......

    先按照x排序(记得把起始位置也加进去)

    然后令f[l][r]表示收集完l~r的球,最后在l的最大收益

    g[l][r]收集完l~r的球,最后在r的最大收益

    然后...然后....然后....

    我就去看题解了。
    好了 进入正题。
    首先我们定义

    f[l][r]表示收集完l~r的球,最后在l的最小损失

    g[l][r]收集完l~r的球,最后在r的最小损失

    最后用总收益减去损失

    在按照x排完序之后

    进行区间dp,由小区间转到大区间

    f[l][r]可以从f[l+1][r]和g[l+1][r]转移而来

    g[l][r]可以从f[l][r-1]和g[l][r-1]转移而来

    我们可以这么理解

    每当我们去接下一个球的时候,其他球在向下掉,相当于我们损失了这些的收益

    那么时间就是x之差的绝对值,然后提前用前缀和预处理v

    就可以直接算出损失了多少收益了

    f[l][r]=min(f[l][r],f[l+1][r]+(sum[n]-sum[r]+sum[l])abs(a[l+1].x-a[l].x));
    f[l][r]=min(f[l][r],g[l+1][r]+(sum[n]-sum[r]+sum[l])
    abs(a[r].x-a[l].x));
    g[l][r]=min(g[l][r],f[l][r-1]+(sum[n]-sum[r-1]+sum[l-1])*abs(a[l].x-a[r].x));

    g[l][r]=min(g[l][r],g[l][r-1]+(sum[n]-sum[r-1]+sum[l-1])*abs(a[r-1].x-a[r].x));

    转移式子就不过多解释了

    然后最后用ans-min(f[1][n],g[1][n])再 /1000就行

    最后注意初始化的时候 嗯

    QWQ我的写法和很多题解都不一样 不过也过了QWQ不太知道是为什么

    for (int i=1;i<=n;i++) f[i][i]=abs(a[i].x-start)sum[n],g[i][i]=abs(a[i].x-start)sum[n];

    上代码 嗯

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    
    using namespace std;
    
    inline int read()
    {
      int x=0,f=1;char ch=getchar();
      while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
      while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
      return x*f;
    }
    
    const int maxn = 1010;
    
    struct Node{
    	int v,x,y;
    };
    
    Node a[maxn];
    int f[maxn][maxn]; //i~j接完 最后在i 
    int g[maxn][maxn]; // i~j接完,最后在j
    int sum[maxn];
    int start,n;
    double ans;
    
    bool cmp(Node a,Node b)
    {
    	return a.x<b.x;
    }
    
    int main()
    {
      n=read();
      start=read();
      memset(f,127/3,sizeof(f));
      memset(g,127/3,sizeof(g));
      for (int i=1;i<=n;i++) a[i].x=read();
      for (int i=1;i<=n;i++) a[i].y=read(),ans+=a[i].y;
      for (int i=1;i<=n;i++) a[i].v=read();
      n++;
      a[n].x=start;
      sort(a+1,a+1+n,cmp);
      for (int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i].v;
      for (int i=1;i<=n;i++) f[i][i]=abs(a[i].x-start)*sum[n],g[i][i]=abs(a[i].x-start)*sum[n];
      for (int i=2;i<=n;i++)
        for (int l=1;l<=n-i+1;l++)
        {
        	int r = l+i-1;
        	f[l][r]=min(f[l][r],f[l+1][r]+(sum[n]-sum[r]+sum[l])*abs(a[l+1].x-a[l].x));
        	f[l][r]=min(f[l][r],g[l+1][r]+(sum[n]-sum[r]+sum[l])*abs(a[r].x-a[l].x));
        	g[l][r]=min(g[l][r],f[l][r-1]+(sum[n]-sum[r-1]+sum[l-1])*abs(a[l].x-a[r].x));
        	g[l][r]=min(g[l][r],g[l][r-1]+(sum[n]-sum[r-1]+sum[l-1])*abs(a[r-1].x-a[r].x));
    	}
      ans=ans-min((double)f[1][n],(double)g[1][n]);
      printf("%.3lf",ans/1000); 
      return 0;
    }
    
  • 相关阅读:
    利用pipe实现进程通信一例
    司机和售票员问题 信号signal注册一例
    HDU 1003
    HDU 1847
    HDU 1846(巴什博弈)
    《断弦》感想
    夺冠概率
    熄灯问题
    HDU 2176(Nim博弈)
    NYOJ 541
  • 原文地址:https://www.cnblogs.com/yimmortal/p/10160606.html
Copyright © 2011-2022 走看看