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;
    }
    
  • 相关阅读:
    A1023 Have Fun with Numbers (20分)(大整数四则运算)
    A1096 Consecutive Factors (20分)(质数分解)
    A1078 Hashing (25分)(哈希表、平方探测法)
    A1015 Reversible Primes (20分)(素数判断,进制转换)
    A1081 Rational Sum (20分)
    A1088 Rational Arithmetic (20分)
    A1049 Counting Ones (30分)
    A1008 Elevator (20分)
    A1059 Prime Factors (25分)
    A1155 Heap Paths (30分)
  • 原文地址:https://www.cnblogs.com/yimmortal/p/10160606.html
Copyright © 2011-2022 走看看