• #4780. 病毒研究


    题目描述

    病毒科学家陈博士正在带领着她的团队在研究病毒,她要研究如何降低病毒的活性。病毒的活性可以用一个整数来表示,但她不知道具体的活性是多少。

    她可以执行 $m+1$ 种操作,对于前 $m$ 种操作,第 $i$ 种操作为花费 $v_i$ 的代价使得病毒 的活性减少 $w_i$;第 $m+1$ 种操作为查看当前病毒所处的状态,不需要花费任何代价。

    病毒一共有 $n$ 种状态。有 $n+1$ 个递增的数 $a_0,a_1,a_2,...,a_n$,其中 $a_0=0$;若病毒的活性 $x$ 满足 $a_{i-1}<xle a_i$,那么这个病毒就处于状态 $i$。同时,保证病毒的活 性不会大于 $a_n$。

    她可以使用每种操作任意多次,但是她不希望病毒完全丧失活性。但是如果在使用了一个操作后,病毒的活性 $le 0$ 了,那研究就失败了。而病毒的活性太高时也不适合研究,只有病毒处于状态 $1$ 时才最适合研究。

    现在,她只知道病毒的活性是 $[1,a_n]$ 中的一个等概率随机的整数。她想知道,在保证病毒不会完全丧失活性的情况下,她使病毒变为状态 $1$ 的过程中,花费代价的期望最少是多少。

    可以发现答案乘 $a_n$ 一定是个整数,输出答案乘 $a_n$ 的值即可。

    如果不能保证病毒不会完全丧失活性,输出 $-1$。

    数据范围

    $1le a_1 < a_2 < ... < a_n le 2000 , 1le T le 10 , 1 le v_i le 10^6$ 。

    题解

    考虑 $ ext{dp}$ : $f[l][r]$ 表示处于 $[l,r]$ 中的数到达 $1$ 状态的期望总和。考虑 $l,r$ 如果不在一个状态就是几个 $ ext{dp}$ 相加,如果在一个状态里的话,就向前平移并且加上向前平移的代价,这样是 $O(n^2m)$ 的。

    考虑减少状态数,我们可以假设一直平移到第一次分割的位置,那么中间这个过程就可以用背包来实现。那我们就只需要记 $f[a_{i-1}+1][x]$和 $f[x][a_i]$ 这样的状态,其中 $x$ 处于 $i$ 状态中。这样效率为 $O(nm)$ 。

    代码

    #include <bits/stdc++.h>
    #define LL long long
    using namespace std;
    const int N=2005;
    const LL G=1e18;
    int T,n,m,z,a[N],b[N];
    LL f[N][N],g[N],s[N];
    LL F(int l,int r){
        if (f[l][r]!=G) return f[l][r];
        for (int x,y,i=1;i<l;i++)
            if (g[i]!=G && (b[l-i]!=b[r-i] || r-i<=a[1])){
                x=l-i;y=r-i;
                LL u=g[i]*(r-l+1)+F(x,a[b[x]])+F(a[b[y]-1]+1,y);
                if (b[x]+1<b[y]) u+=s[b[y]-1]-s[b[x]];
                f[l][r]=min(u,f[l][r]);
            }
        return f[l][r];
    }
    void work(){
        scanf("%d%d",&n,&m);
        memset(b,0,sizeof b);
        for (int i=1;i<=n;i++)
            scanf("%d",&a[i]),
            b[a[i]+1]++;z=a[n];b[0]=1;
        for (int i=1;i<=z;i++)
            b[i]+=b[i-1],g[i]=G;
        for (int x,y;m--;){
            scanf("%d%d",&x,&y);
            for (int i=y;i<=z;i++)
                g[i]=min(g[i],g[i-y]+x);
        }
        for (int i=1;i<=z;i++)
            for (int j=i;j<=z;j++) f[i][j]=G;
        for (int i=1;i<=a[1];i++)
            for (int j=i;j<=a[1];j++) f[i][j]=0;
        for (int x,y,i=2;i<=n;i++){
            x=a[i-1]+1;y=a[i];
            for (int r=x;r<=y;r++) f[x][r]=F(x,r);
            for (int l=x;l<y;l++) f[l][y]=F(l,y);
            if (f[x][y]==G){puts("-1");return;}
            s[i]=s[i-1]+f[x][y];
        }
        printf("%lld
    ",s[n]);
    }
    int main(){for (cin>>T;T--;work());return 0;}
  • 相关阅读:
    HTML+CSS面试题汇总(持续更新)
    vue-router
    MongoDB
    闭包
    JavaScript的严格模式
    IO题目
    Java 题目集 编程
    Java题目集 函数
    2.面向对象基础-04继承
    2.面向对象基础-03Java数组
  • 原文地址:https://www.cnblogs.com/xjqxjq/p/12727407.html
Copyright © 2020-2023  润新知