jzoj 2017.10.05 模拟赛

T1:
【2012.02.25普及组】探索的奶牛:

题目大意:
农场里有N只奶牛,当碰到路口时,可能会分成两部分(不能为空),每一部分都继续前进,当碰到另一个路口时,再分成两部分,如此反复下去。。。
计算最终被分成多少支队伍,要求任意2部分的差为K。

例:
有6只奶牛,分裂时两个小组的人数差为2.
输出说明: 最终有3支队伍分别为(数量分别为2,1,3)

   6
  / \
 2   4
    /  \
   1    3

1<=N<=1,000,000,000

题解:
这题其实就是一个递归搞定
注意一下情况:
①不能分成2部分就返回0
②能分成2部分但差不为K就返回1(它本身)
③能分成2部分且差为K,递归过去
④考虑有部分<=0的情况
然后如果最后什么都不能分就输出1,否则就输出递归结果,因为对于N,K为3 3,那么就是第一种情况,就是0,那么我们要输出的是1,注意!

var
    n,m,k:longint;

function dfs(dep:longint):longint;
var
    i,j,k:longint;
begin
    dfs:=0;
    i:=dep div 2-m div 2;
    j:=(dep+1) div 2+m div 2;
    if (j-i=m) and (i+j=dep) then
    begin
       k:=0;
       if i>0 then
       begin
         if (i>=m+2)
              then dfs:=dfs+dfs(i)
              else dfs:=dfs+1;
       end;
       if j>0 then
       begin
         if (j>=m+2)
              then dfs:=dfs+dfs(j)
              else dfs:=dfs+1;
       end;
    end else if i+j=dep then dfs:=1;
    exit(dfs);
end;

begin
    readln(n,m);
    k:=dfs(n);
    if k=0 then writeln(1)
           else writeln(k);
end.

T2:
【2012.02.25普及组】单词:
题目大意:
从前有N只奶牛,他们想知道自己名字的好听度,每个名字都是一个字符串ai。
一个好名字的集合,数量为M,奶牛的名字中每包含一个好名字(“包含”不一定要求连续),那么它的好听度就加1。
请你帮FJ计算每个奶牛名字的好听度。

名字为长度不超过1000的英文字母组成
1<=N<=1000,1<=M<=100
好名字的长度不超过30
所有的名字都不区分大小写

题解:
这题我们直接去枚举:
i枚举好名字,j枚举牛,k枚举名字的字符,找到就累加给f[j]即可
时间复杂度:O(M*∑length(ai))

var
    a:array [0..1001] of ansistring;
    f:array [0..1001] of longint;
    i,j,k,l,n,m:longint;
    x:string;
begin
    readln(n,m);
    for i:=1 to n do
      begin
           readln(a[i]);
           a[i]:=lowercase(a[i]);
      end;
    for i:=1 to m do
      begin
            readln(x);
            x:=lowercase(x);
            for j:=1 to n do
              begin
                   k:=1;
                   l:=0;
                   while l<length(a[j]) do
                   begin
                        inc(l);
                        if a[j][l]=x[k] then inc(k);
                        if k>length(x) then break;
                   end;
                   if k>length(x) then inc(f[j]);
              end;
      end;
    for i:=1 to n do writeln(f[i]);
end.

T3:
【2012.02.25普及组】牛车:
题目大意:
有N 头牛准备在高速公路上赛车,第i个赛车的车速为S[i] 千米/小时,高速公路上一共有M个赛车道。
同车道前面有X个赛车,这辆赛车的车速就会降低D*X千米/小时,当然不会降到0以下,所以车速应该max(S[i]-D*X, 0)。
由于车距很大,所以即使后面的车比前面的车快,你也不用担心会发生碰撞。
高速公路上有一个最低限速L,凡是低于该速度的车不允许在高速上行驶的(注意:减速后的速度若低于L也不能在高速上行驶),现在请你来计算一共可以多少辆赛车在高速公路上行驶。

30%的数据:N≤20,M=1;
60%的数据:N≤1000,M≤10;
100%的数据:1≤N≤50000,1≤M≤100,1≤S[i], L≤10^6,0≤D≤5000。
编号为1..N

题解:
这题我们就先对车的速度从小到大;
因为排序保证了结果的最优,所以枚举一个车速s[i],一个赛道,能放就放,不能就新开一条车道,车道满了或者每个车道都低于限速就走。
时间复杂度:O(N log2 N+N)

var
    a:array [0..50001] of longint;
    sum:array [0..101] of longint;
    ans,n,m,d,l,i,j,k:longint;

procedure qsort(l,r:longint);
var
    i,j,mid:longint;
begin
    if l>=r then exit;
    i:=l; j:=r;
    mid:=a[(l+r) div 2];
    repeat
         while a[i]<mid do inc(i);
         while a[j]>mid do dec(j);
         if i<=j then
           begin
                a[0]:=a[i];a[i]:=a[j];a[j]:=a[0];
                inc(i); dec(j);
           end;
    until i>j;
    qsort(i,r);
    qsort(l,j);
end;

begin
    readln(n,m,d,l);
    for i:=1 to n do
      readln(a[i]);
    qsort(1,n);
    sum[0]:=0;
    for i:=1 to n do
      begin
            j:=0;
            while j<sum[0] do
            begin
                 inc(j);
                 if a[i]-d*sum[j]>=l then break;
            end;
            if (a[i]-d*sum[j]>=l) and (j<>0)
               then inc(sum[j])
               else if (sum[0]+1<=m) and (a[i]>=l) then
                    begin
                         inc(sum[0]);
                         sum[sum[0]]:=1;
                    end;
      end;
    for i:=1 to sum[0] do
      ans:=ans+sum[i];
    writeln(ans);
end.

T4:
【2012.02.25普及组】危险系数:
题目大意:
在一条船上,海上有N个岛,编号为1..N,现在他的任务是按照一个给定访问次序A_1,A_2,….A_M去探索这M个岛屿,已经知道任意两个岛屿之间的危险系数,让你找出一个探索序列,只需满足你的探索序列包含给定的A_1..A_M这个序列就可以(不一定要连续),使得总的危险系数最小。

1<=N<=100
2<=M<=10,000

题解:
这题我们不难发现,对于一个
数列a1 a2 a3 a4
要满足这个序列为子序列
就是在这个基础上瞎搞~~
即 a1 b1 b2 a2 b3 a3 b4 b5 a4诸如此类
所以我们要找的最小值
就是a1到a2的最短路,a2到a3的最短路,a3到a4的最短路,a5到……的总和

所以就很容易做了,
一个floyd然后直接求和

时间复杂度:O(N^3+M)

var
     f:array [0..101,0..101] of longint;
     c:array [0..10001] of longint;
     ans,i,j,k,n,m:longint;

function min(aa,bb:longint):longint;
begin
     if aa>bb then exit(bb);
     exit(aa);
end;

begin
     readln(n,m);
     for i:=1 to m do readln(c[i]);
     for i:=1 to n do
     begin
         for j:=1 to n do read(f[i,j]);
         readln;
     end;

     for k:=1 to n do
       for i:=1 to n do
         for j:=1 to n do
          if (i<>j) and (i<>k) and (j<>k) then
             f[i,j]:=min(f[i,j],f[i,k]+f[k,j]);

     ans:=0;
     for i:=1 to m-1 do
       ans:=ans+f[c[i],c[i+1]];
     writeln(ans);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值