JZOJ 8.15 B組總結

NO.1 平臺

Description
  Alice要搭建平臺,平臺不能漂在空氣中,必須要有兩根柱子支撐,具體地說,每個平臺的兩端必須由一根柱子支撐,柱子的另一端在地板或另一個平臺上。
  給你平臺的放置位置(如下左圖所示),每個平臺的位置由它的高度(離地面的垂直距離)和水平方向兩個端點的座標決定,每根柱子必須安放在離端點0.5個單位的位置,如下右圖所示。
  這裏寫圖片描述

  編程計算所需柱子總長是多少。


思路:暴力枚舉
暴力O(n^2)枚舉,任意一個平臺,對除它外的任意平臺的貢獻就好了


代碼:

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

NO.2 單足跳

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的最小花費。
Sample Input

輸入1:
6
1
2
3
4
5
6

輸入2:
8
2
3
4
3
1
6
1
4

Sample Output

輸出1:
12

輸出2:
14


思路:dp
設f[i][j]爲跳了i步,當前在第j個格子的最小花費
那麼就枚舉跳了多少步
再轉移一下就好了


代碼:

var n,ans,i,j:longint;
    v:array[0..1001]of longint;
    f:array[0..1001,0..1001]of longint;
begin
  readln(n);
  ans:=maxlongint;
  for i:=1 to n do readln(v[i]);
  fillchar(f,sizeof(f),$7f);f[1,2]:=v[2];
  for i:=1 to n-1 do
    begin
      for j:=n downto i+1 do if f[i,j]+v[j-i]<f[i,j-i] then f[i,j-i]:=f[i,j]+v[j-i];
      for j:=1 to n-i do if f[i,j]<>2139062143 then f[i+1,i+j+1]:=f[i,j]+v[i+j+1];
      if f[i,n]<ans then ans:=f[i,n];
    end;
  write(ans);
end.

NO.3 生日聚餐

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
輸出最多能做多少道菜。
Sample Input

輸入1:
2 100
10 8 10 10 13 11
12 20 6 10 17 24

輸入2:
3 65
10 5 7 10 13 14
10 5 8 11 14 15
10 5 9 12 15 16

Sample Output

輸出1:
5

輸出2:
2

Hint
【樣例說明】
  樣例1中,Alice購買第一種原料3個小包裝和1個大包裝,購買第二種原料1個小包裝和2個大包裝,一共花費3×10+1×11+1×10+2×24=99元。
  兩種原料的數量分別爲51個(8+3×10+11)和60個(20+1×6+2×17),可以做出5道菜。


思路:二分+貪心
每次二分求出一個mid,表示全部菜至少要做mid道
再用貪心,求出每一道菜最小需要的錢數,加起來,判斷一下是否符合條件,符合l=mid+1 不符合 r=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;
}

NO.4 數學題

Description
  當Alice在瀏覽數學書時,看到一個等式A=S,奇怪的是A和S並不相等。Alice發現可以通過在A中添加加號“+”從而使得等式成立。
  編程計算最少需要插入多少加號使得等式成立。允許每個數有多個前導0。
Input
  輸入第一行包含一個等式形式爲A=S。
  A和S都是沒有前導0的正整數,並保證不相同。
  A最多有1000位。
  S<=5000。
  輸入保證有解。
Output
  輸出最少需要插入的加號數量。
Sample Input

輸入1:
143175=120

輸入2:
5025=30

輸入3:
999899=125

Sample Output

輸出1:
2

輸出2:
1

輸出3:
4


思路:DP
設f[i][j]爲前i位和爲j需要的最少加號個數
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]);
l爲枚舉到第l位,sum爲第i~l位的數字和,k爲a的長度


代碼:

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;

procedure init;
begin
  readln(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;

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;

begin
  init;
  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;
  writeln(ans);
end.
發佈了263 篇原創文章 · 獲贊 423 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章