炸弹 (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;
}