【UOJ 149】机房人民大团结

【题目描述】:

最近,机房出了一个不团结分子:Dr.Weissman。他经常欺骗同学们吃一种“教授糖豆”,使同学们神志不清,殴打他人,砸烂计算机,破坏机房团结。幸运地,一个和谐家认清了Dr.Weissman的本质。机房人民团结在一起,共同对抗Dr.Weissman及“教授糖豆”。

同学们十分具有社会责任感:他们害怕“教授糖豆”流向社会,导致动乱。于是,刚才提到的和谐家身先士卒,为了实验,品尝“教授糖豆”。

每个“教授糖豆”的性质都有所不同。同志们已经研究出每个糖豆对人的影响。具体地,每个糖豆都有一个破坏值,吃掉这颗糖豆后,身先士卒的和谐家会对机房造成一定的破坏,破坏程度为先前累积的破坏值加上本次食用糖豆的破坏值,而且这颗“教授糖豆”的破坏值会加入累积。为了减小实验造成的破坏,同学们准备了几颗“治疗糖豆”,功能是无条件将累积的“破坏值”清零。(注意:吃了“教授糖豆”后会立即开始破坏,破坏结束后才有可能吃“治疗糖豆”)

由于实验要求,和谐家只能按照给定的顺序吃掉“教授糖豆”,但可以随时吃掉一颗或多颗“治疗糖豆”。

你能帮助和谐家同志尽量减小实验所造成的破坏吗?

【输入描述】:

第一行,两个数,用空格,分隔开,一个n,一个m。(n,m均为正整数。)n表示“教授糖豆”的数目,m表示“治疗糖豆”的数目。

剩余n行,每行1个正整数,表示“教授糖豆”的破坏值。和谐家必须按照给定的顺序,一次一个,吃掉所有“教授糖豆”。

【输出描述】:

一行,一个数,表示实验造成的最小破坏。

【样例输入】:

3 1
1 2 3

【样例输出】:

7

【样例说明】:

1+(1+2)+(此时吃了“治疗糖豆”累积值清零)+3 = 7

【时间限制、数据范围及描述】:

时间:1s 空间:256M

对于100%的数据,1<=n<=100,m<=n

所有破坏值的加和小于10^9。

 

题解:奇怪的DP增加了

 

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=102; 
const int oo=0x3f3f3f3f;
int n,m;
ll ans=(1LL<<60);
int a[N],sum[N],vis[N];

void wow(){
    int tot=0;
    ll sum=0;
    for(int i=1;i<=n;i++){
        sum+=(ll)(a[i]+tot);
        if(vis[i]==1) tot=0;
        else tot+=a[i];
    } 
    ans=min(ans,sum);
}

void work1(){
     int xx=pow(2,n+1);
    for(int i=1;i<xx;i++){
        //cout<<i<<endl;
        int x=i; int nu=0;
        for(int j=1;j<=n;j++)
            if((1<<(j-1)&x)!=0) { vis[j]=1; nu++; }
            else vis[j]=0;
        if(nu==m) wow();
    }
    printf("%d\n",ans);
}
ll f[105][105][105];
void work2(){
    //cout<<42;
    for(int i=0;i<=n;i++)    
        for(int j=0;j<=n;j++)
            for(int k=0;k<=n;k++)
                f[i][j][k]=(1LL<<60);

    f[0][0][0]=0;
    for(int i=1;i<=n;i++){
        for(int j=0;j<i;j++)
            for(int k=0;k<i;k++)
                f[i][j][k]=f[i-1][j][k]+ll(sum[i]-sum[k-1]);
        for(int j=1;j<=i;j++)
            for(int k=0;k<i;k++)
                f[i][j][i]=min(f[i][j][i],f[i-1][j-1][k]+a[i]);
    }
    for(int i=0;i<=m;i++)
        for(int j=0;j<=n;j++)
            ans=min(ans,(ll)f[n][i][j]);
    printf("%lld\n",ans);
}
int main(){
 
    scanf("%d %d",&n,&m);
    //cout<<n;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        sum[i]=sum[i-1]+a[i]; 
    }
    //if(n<=20) work1();
    //else 
    work2();
    //else cout<<"66666666";
    return 0;
}

 

posted @ 2020-11-24 14:16  #Cookies#  阅读(117)  评论(0编辑  收藏  举报