【DP】TEST20170406

10 篇文章 0 订阅

炸弹 (Bomb.pas/c/cpp Time:1s Memory:256M)

问题描述

    高老大又在鼓捣炸弹了,这不,启动了一个了。英明英勇的老大又在跟他的部下们表演空手光速拆炸弹了。
    炸弹上是一个圆盘,圆盘上顺时针写着 N 个数。其实这个炸弹就是要求从中选择若干个连续的数(注意每个数最多只能选一次)加起来,使得这些数字的和最大,然后输入这个最大的和,计时就会停止。现在你被老大要求上台表演,时间是 1s,任务就交给你了。

输入

    输入文件名为 Bomb.in。
    输入第一行包含一个正整数 N,表示数字的个数。
    第二行包含 N 个整数,为所给的数字。。

输出

    输出文件名为 Bomb.out。
    输出包含一个整数,为最大的可以得到的和。

输入样例

8
2 -4 6 -1 -4 8 -1 3

输出样例

14

数据范围

对于 30%的数据 1<=N<=200;
对于 70%的数据 1<=N<=10000;
对于 100%的数据 1<= N<=100000 , 答案在 longint 范围内。

分析

    若不考虑环,f[i]表示[1,i]区间内最大连续和f[i]=max(a[i],max(f[i-1]+a[i],0));若考虑环则倍长数组,从a[n]分别向左右取数,再对应相加,取最大值。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int sz = 100000*2+5;
int n,ans=0,a[sz],h[sz],g[sz],f[sz];
int main()
{
    freopen("bomb.in","r",stdin);
    freopen("bomb.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    {
        scanf("%d",&a[++a[0]]);
        if(!a[a[0]])--a[0];
        else if(a[a[0]-1]*a[a[0]]>0&&a[0]!=1)
            a[a[0]-1]+=a[a[0]],--a[0];
    }
    for(int i=1;i<=a[0];++i)
        f[i]=max(a[i],max(f[i-1]+a[i],0));
    for(int i=1;i<=a[0];++i)
        ans=max(ans,f[i]);
    for(int i=1;i<=a[0];++i)
        a[i+a[0]]=a[i];
    for(int i=a[0];i>=1;--i)
    {
        g[i]=g[i+1]+a[i];
        h[i]=max(h[i+1],g[i]);
    }
    g[a[0]+1]=h[a[0]+1]=a[a[0]+1];
    for(int j=a[0]+2;j<=a[0]<<1;++j)
    {
        g[j]=g[j-1]+a[j];
        h[j]=max(h[j-1],g[j]);
    }
    for(int i=1;i<=a[0];++i)
        ans=max(ans,h[i]+h[i+a[0]-1]);
    printf("%d\n",ans);
    return 0;
}

操练 (Training.pas/c/cpp Time:1s Memory:256M)

问题描述

    高老大有一个 N*N 的广场,被均分成 N*N 个格子。其中某些格子种上了树。为了维护世界的和平,为了贯彻和平与发展的原则,老大不得不开始操练部下了。部下们必须站在广场中某没种上树个格子中,而且一个格子内不允许有两个人站着。同时,为了显得整齐划一,部下们要维护一个方阵的阵型,也就是 N*N 的广场内的一个 X*Y 的矩形(该矩形的长和宽必须与广场的长和宽平行),每个格子上都必须有一个部下。现在老大想知道,一次最多操练多少个部下?

输入

    输入文件名为 Training.in。
    输入第一行两个正整数 N 和 M,代表广场的长和宽。
    下接一个 N 行 M 列的字符矩阵,若第 I 行第 J 列为‘0’则代表该格子上有一颗树。

输出

    输出文件名为 Training.out。输出一次最多能够操练的部下个数。

输入样例

2
11
11

输出样例

4

数据范围

对于 80%的数据,N<=250;
对于 100%的数据,N <= 1000。

分析

    (见noi2003集训队论文)最大子矩形|栈

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int sm=1000;
int s,n,ans,pre,h[sm][sm],l[sm][sm],r[sm][sm],a[sm][sm];
struct tree{
    int x,y;
}e[sm];
bool cmp(tree a,tree b){return a.x<b.y;}
int main()
{
    freopen("training.in","r",stdin);
    freopen("training.out","w",stdout);
    scanf("%d",&n);
    for(int i=0;i<=n;++i)
        for(int j=0;j<=n;++j)
            r[i][j]=n+1;
    for(int i=1;i<=n+1;++i)
    {
        pre=0;
        for(int j=1;j<=n+1;++j)
        {
            if(i!=n+1&&j!=n+1)scanf("%1d",&a[i][j]);
            if(!a[i][j])
            {
                for(int k=pre+1;k<j;++k)l[i][k]=pre;
                for(int k=pre+1;k<j;++k)r[i][k]=j;
                pre=j;
            }
        }
    }
    for(int i=1;i<=n;++i)
    {   
        for(int j=1;j<=n;++j)
        {
            if(i==1)
            {
                if(a[i][j])h[i][j]=1;
            }
            else 
            {
                if(a[i-1][j]&&a[i][j])h[i][j]=h[i-1][j]+1;
                else if(a[i][j])h[i][j]=1;
            }   
            if(i==1||(a[i][j]&&a[i-1][j]))
            {
                l[i][j]=max(l[i-1][j],l[i][j]);
                r[i][j]=min(r[i-1][j],r[i][j]);
            }
            else 
            if(!a[i][j])l[i][j]=r[i][j]=j;
            ans=max(ans,(r[i][j]-l[i][j]-1)*h[i][j]);
        }
    }
    printf("%d\n",ans);
    return 0;
}

战争(War.pas/c/cpp Time:1s Memory:256M)

问题描述

    高老大要打团战了。他要召集 N(N 是奇数)个人去组织一场战争。现在高老大的手下有 T 个人,每个人都有一个战斗力值和影响力值。当这 N 个人的影响力值之和超过 M 的时
候,必然会引起巨大的社会动荡。为了爱与和平,老大明智地决定,不引起巨大的社会动荡。同时,英明的老大发现,一个团队整体能力等于这 N 个人的战斗力的中位数,中位数越高则战斗力越强。现在老大想知道,这 N 个人的团队整体能力最大为多少。

输入

    输入文件名为 War.in。
    输入第一行为三个正整数 N,T,M,意义如上述。
    后接 T 行,每行两个正整数 Wi 和 Vi,代表每个人的战斗力值和影响力值。

输出

    输出文件名为 War.out。
    输出一行一个整数,代表这 N 个人的团队最大的整体能力。无解输出-1。

输入样例

3 5 70
30 25
50 21
20 20
5 18
35 30

输出样例

35

样例解释

    选第 2、4、5 个人,影响力 21+18+30=69<=70,同时该团队的整体能力为最高的 35。

数据范围

30%的数据:1≤N≤8,1≤M≤28。
100%的数据:1≤N≤16,1≤M≤120。1≤C≤ 108

代码

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int sm = 100000+10;
const int inf = 0x3f3f3f3f;
int n,t,m,k,ans=inf,tmp;
struct sol{
    int w,v;
}a[sm];
bool cmp(sol x,sol y){return x.w<y.w;}
long long f[sm],g[sm];
priority_queue<int>q;
int main()
{
    freopen("war.in","r",stdin);
    freopen("war.out","w",stdout);
    scanf("%d%d%d",&n,&t,&m);
    tmp=(n-1)>>1;
    for(int i=1;i<=t;++i)
        scanf("%d%d",&a[i].w,&a[i].v);
    sort(a+1,a+t+1,cmp);

    for(int i=1;i<=tmp;++i)
        f[i]=inf,q.push(a[i].v),k+=a[i].v;

    f[tmp+1]=k;
    for(int i=tmp+2;i<=t-tmp;++i)
    {
        if(q.top()>a[i-1].v)
        {
            f[i]=f[i-1]-q.top()+a[i-1].v;
            q.pop();
            q.push(a[i-1].v);
        }
        else f[i]=f[i-1];
    }

    while(!q.empty())q.pop();
    k=0;
    for(int i=t;i>=t-tmp+1;--i)
        g[i]=inf,q.push(a[i].v),k+=a[i].v;
    g[t-tmp]=k;
    for(int i=t-tmp-1;i>=1;--i)
    {
        if(q.top()>a[i+1].v)
        {
            g[i]=g[i+1]-q.top()+a[i+1].v;
            q.pop();
            q.push(a[i+1].v);
        }
        else g[i]=g[i+1];
    }
    for(int i=1;i<=t;++i)
        if(g[i]+f[i]+a[i].v<=1ll*m)
            ans=a[i].w;
    if(ans!=0x3f3f3f3f)printf("%d\n",ans);
    else printf("-1\n");
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值