• P2654 原核生物培养


    P2654 原核生物培养

    题目描述

    W教授最近正在研究一种原核生物,这种生物的生长方式很奇特,只能通过吃掉同类而生长。两个该种生物相遇,较大质量的会把较小的吃掉(相同的话就看RP了),吃掉后较大的生物的质量会变为两只原核生物重量之和,但这个过程会消耗酶,消耗的酶近似为它们重量之和。
    W教授现在有n只原核生物,他每次会从培养皿中取重量最小的m个生物进行实验,让它们自相残杀。
    实验的操作是这样的,教授将这m个原核生物按某种重量大小的顺序放在一个环形的管道里,然后给其中相邻两只原核生物酶,如此反复。最后把剩下的那只放回培养皿,接着进行下次实验。W教授希望经过k次实验后耗能最少。输入数据保证,不会出现生物不够的情况。

    输入输出格式

    输入格式:
    第一行有三个整数,分别为n,m,k
    第二行有n个整数,代表最初n个生物的重量
    接下来的k行,每行m个整数,第i+2行的第j个数代表第i次实验的第j小的生物放在哪个位置。例如m=5,第三行为,14235 代表最小的生物放在第一个位置,第二小的放第四个…最大的放在第五个位置(和第一个位置相邻)

    输出格式:

    只有一个整数,代表k次实验之后最小消耗酶的量。

    输入输出样例

    输入样例#1:
    10 2 3
    1 2 3 4 5 6 7 8 9 10
    1 2
    1 2
    1 2
    输出样例#1:
    18

    说明

    1<n<=1000,1<=m<=10,1<=k<=100。数据保证结果不超过2^31。

    样例解释:
    第一次是用重量为1 2 消耗酶3 变为一个重量3
    第二次是用重量为3 3 消耗酶6 变为一个重量6
    第三次是用重量为4 5 消耗酶9 变为一个重量9
    所以消耗总酶为18

    做法
    优先队列加dp
    首先题目要求每次从序列中取出最小的m个元素然后一一合并
    把仅剩的最后一个元素重新放回序列
    重复这个过程k遍

    所以只需要进行k遍石子合并就可以
    然后用优先队列维护序列

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #define N 105
    #define INF 0x3f3f3f3f
    using namespace std;
    
    priority_queue<int,vector<int>,greater<int> > q;
    
    int a[N],b[N],f[N][N],s[N];
    int n,m,k,sum;
    
    int read(){
        char ch=getchar();int s=0;
        for(;!isdigit(ch);ch=getchar());
        for(;isdigit(ch);s=s*10+ch-'0',ch=getchar());
        return s;
    }
    
    int main(){
        cin>>n>>m>>k;
        for(int i=1;i<=n;i++)
            q.push(read());
        while(k--){
            int all=0;
            for(int i=1;i<=m;i++){
                int x=read();
                a[x]=q.top();
                q.pop();
                all+=a[x];
            }
            q.push(all);
            for(int i=1;i<=m;i++)
                a[m+i]=a[i];
            for(int i=1;i<=m<<1;i++)
                s[i]=s[i-1]+a[i];
            for(int l=2;l<=m;l++)
                for(int i=1;i+l-1<m<<1;i++){
                    int j=i+l-1; f[i][j]=INF;
                    for(int k=i;k<j;k++){
                        int ans=f[i][k]+f[k+1][j]+s[j]-s[i-1];
                        if(f[i][j]>ans)
                            f[i][j]=ans;
                    }
                }
            int minn=INF;
            for(int i=1;i<=m;i++)
                if(f[i][i+m-1]<minn)
                    minn=f[i][i+m-1];
            sum+=minn;
        }
        cout<<sum;
        return 0;
    }
    
    
  • 相关阅读:
    【开发者笔记】C#连接mysql问题记录
    【开发者笔记】揣摩Spring-ioc初探,ioc是不是单例?
    【开发者笔记】c# 调用java代码
    【数据库乱码】记录一下数据库乱码问题
    字符函数
    单行函数和多行函数
    rownum和rowid伪列
    排序子句
    单引号的转义
    逻辑运算符
  • 原文地址:https://www.cnblogs.com/qdscwyy/p/7987582.html
Copyright © 2020-2023  润新知