JZOJ2017.08.15 B组

T1

NO.1 平台

Description
  Alice要搭建平台,平台不能漂在空气中,必须要有两根柱子支撑,具体地说,每个平台的两端必须由一根柱子支撑,柱子的另一端在地板或另一个平台上。
  给你平台的放置位置(如下左图所示),每个平台的位置由它的高度(离地面的垂直距离)和水平方向两个端点的坐标决定,每根柱子必须安放在离端点0.5个单位的位置,如下右图所示。

 编程计算所需柱子总长是多少。

思路:

暴力,存储每个平台对每个点的贡献。

代码:

uses math;
var n,i,maxl,maxr,j,ans:longint;
    t,l,r:array[0..101]of longint;
begin
  read(n);
  for i:=1 to n do readln(t[i],l[i],r[i]);
  for i:=1 to n do
  begin
    maxl:=t[i];
    maxr:=t[i];
    for j:=1 to n do
      if (i<>j)and(t[i]>t[j]) then
      begin
        if (l[i]<r[j])and(l[i]>=l[j]) then maxl:=min(maxl,t[i]-t[j]);
        if (r[i]>l[j])and(r[i]<=r[j]) then maxr:=min(maxr,t[i]-t[j]);
      end;
    ans:=ans+maxl+maxr;
  end;
  write(ans);
end.

T2

Description
  游戏在一行N个方块中进行,编号为1到N,一开始Alice在方块1中,第一次只能跳到方块2中,接下来每一次跳跃必须满足以下两个限制:
  (1) 如果是向前跳(即跳到比现在编号大的方块),跳跃距离必须比上一次要大1;
  (2) 如果是向后跳(即跳到比现在编号小的方块),跳跃距离必须跟上一次一样。
  例如,第一次跳跃后,Alice可以跳回1也可以跳到4。
  每进入一个方块,Alice必须支付一定的费用,Alice的目标花最少的钱从方块1跳到方块N。编程计算最小的花费。
Input
  第一行包含一个整数N(2<=N<=1000),表示方块的个数。
  接下来N行,每行包含一个不超过500的正整数表示进入该方块的费用。
Output
  输出Alice跳到N的最小花费。

思路:

dp
设f[i][j]为跳了i步,当前在第j个格子的最小花费

代码:

var f:array[-10..1100,-10..1100] of longint;
    a:array[-10..1100] of longint;
    ans,maxn,n:longint;
procedure main;
var i,j:longint;
begin
  for i:=1 to n-1 do
  begin
    for j:=n downto i+1 do if f[i,j]+a[j-i]<f[i,j-i] then
      f[i,j-i]:=f[i,j]+a[j-i];
    for j:=1 to n-i do if f[i,j]<maxn then
      f[i+1,i+j+1]:=f[i,j]+a[i+j+1];
    if f[i,n]<ans then ans:=f[i,n];
  end;
end;
procedure init;
var i:longint;
begin
  read(n);
  for i:=1 to n do begin read(a[i]); ans:=ans+a[i] end;
  ans:=ans*10;   maxn:=ans;
  fillchar(f,sizeof(f),$7f div 3); f[1,2]:=a[2];
end;
begin
  init;
  main;
  write(ans);
end.

T3

Description
  Alice在餐馆里当服务员,今天是她生日,她请求厨师帮她准备生日晚餐,晚餐由N种原料做成,每道菜所需每种原料的数量是一样的。
  厨房里有一些原料,但不够,Alice还需要从旁边的超市中购买一些回来。超市里什么原料都有,每种原料都分大包装和小包装。Alice有M元钱,她想利用这M元钱购买原料使得能做出最多的菜。
Input
  第一行包含两个整数N和M(1<=N<=100,1<=M<=100000),接下来N行,每行包含6个正整数,用来描述这种原料的信息,具体如下:
  (1) X:10<=X<=100,表示一道菜中必须含有这种原料的数量;
  (2) Y:1<=Y<=100,表示这种原料厨房已有的数量;
  (3) Sm:1<=Sm<=100,表示超市里小包装中含有这种原料数量;
  (4) Pm:10<=Pm<=100,表示小包装的价格;
  (5) Sv:1<=Sv<=100,表示超市里大包装中含有这种原料数量;   
(6) Pv:10<=Pv<=100,表示大包装的价格;
Output
输出最多能做多少道菜。

思路:

二分答案 +贪心

二分mid,用贪心看合不合法。

代码:

#include<cstdio>
#include<iostream>
using namespace std;
int x[101],y[101],sm[101],pm[101],sv[101],pv[101],f[101][100001];
int mid,n,m,l,r;
bool pd(int q)
{
    int s[101],k,ans,sum=0;
    for (int i=1;i<=n;i++) s[i]=q*x[i]-y[i];
    for (int i=1;i<=n;i++)
    {   
        ans=2147483647;
        for (int j=0;j<=s[i]/sm[i]+2;j++)
        {
            if (s[i]-j*sm[i]>0) k=(s[i]-sm[i]*j-1)/sv[i]+1; else k=0;
            ans=min(ans,j*pm[i]+k*pv[i]);
            if (j*pm[i]>=ans) break;
        }
        sum+=ans;
        if (sum>m) return false;
    }
    if (sum<=m) return true;
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%d%d%d%d%d%d",&x[i],&y[i],&sm[i],&pm[i],&sv[i],&pv[i]);
    l=0; r=m;
    while (l<r)
    {
        mid=(l+r)>>1;
        if (pd(mid)) l=mid+1; else r=mid;
    }
    printf("%d\n",l-1);
    return 0;
}

T4

Description
  当Alice在浏览数学书时,看到一个等式A=S,奇怪的是A和S并不相等。Alice发现可以通过在A中添加加号“+”从而使得等式成立。
  编程计算最少需要插入多少加号使得等式成立。允许每个数有多个前导0。
Input
  输入第一行包含一个等式形式为A=S。
  A和S都是没有前导0的正整数,并保证不相同。
  A最多有1000位。
  S<=5000。
  输入保证有解。
Output
  输出最少需要插入的加号数量。

思路:

DP
设f[i][j]为前i位和为j需要的最少加号个数
f[l,j+sum]:=min(f[l,j+sum],f[i,j]+1);

代码:

uses math;
var s,st,s2:ansistring;
    s1:string[1];
    a:array[0..1000]of longint;
    f:array[0..1000,0..5000]of longint;
    i,j,k,m,n,t,ans,l,sum,p,w:longint;
function make:longint;
begin
  s2:='';
  for p:=t to l do
  begin
    str(a[p],s1);
    s2:=s2+s1;
  end;
  val(s2,sum);
  if j+sum<=n then
    begin
      f[l,j+sum]:=min(f[l,j+sum],f[i,j]+1);
      if (j+sum=n)and(l=k) then ans:=min(ans,f[i,j]);
    end
  else exit(1);
  exit(0);
end;
procedure init;
begin
  read(s);
  st:=copy(s,1,pos('=',s)-1);
  val(copy(s,pos('=',s)+1,length(s)),n);
  for i:=1 to length(st) do
    begin
      k:=k+1;
      a[k]:=ord(s[i])-48;
    end;
  for i:=0 to 1000 do for j:=0 to 5000 do f[i,j]:=maxlongint;
  f[0,0]:=0;
  ans:=maxlongint;
end;
procedure main;
begin
  for i:=0 to k do
    for j:=0 to n do
      if f[i,j]<maxlongint then
      begin
        t:=i+1;
        while (a[t]=0)and(t<k) do t:=t+1;
        w:=min(k,t+length(st));
        for l:=t to w do if make=1 then break;
      end;
  write(ans);
end;
begin
  init;
  main;
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值