JZOJ2017.07.10 C组

59 篇文章 0 订阅

T1

题目描述

一个十进制整数被叫做权势二进制,当他的十进制表示的时候只由0或1组成。例如0,1,101,110011都是权势二进制而2,12,900不是。
当给定一个n的时候,计算一下最少要多少个权势二进制相加才能得到n。

思路:

其实问题可以转换为求数字字符串里最大的那个数
我们可以把数字拆分,比较,,就,AC!

代码:

var max,n,i,t:longint;
begin
  assign(input,'a.in');
  assign(output,'a.out');
  reset(input);
  rewrite(output);
  read(n);
  for i:=1 to n do
  begin
    max:=0;
    read(t);
    while t>0 do
    begin
      if t mod 10>max then max:=t mod 10;
      if max=9 then break;
      t:=t div 10;
    end;
    writeln(max);
  end;
  close(input);
  close(output);
end.

T2

题目描述:

KC邀请他的两个小弟K和C玩起了数字游戏。游戏是K和C轮流操作进行的,K为先手。KC会先给定一个数字Q,每次操作玩家必须写出当前数字的一个因数来代替当前数字,但是这个因数不能是1和它本身。例如当前数字为6,那么可以用2,3来代替,但是1和6就不行。现在规定第一个没有数字可以写出的玩家为胜者。K在已知Q的情况,想知道自己作为先手能不能胜利,若能胜利,那么第一次写出的可以制胜的最小数字是多少呢?整个游戏过程我们认为K和C用的都是最优策略。

思路:

三种情况:
1.质数 K win
2.两个质数相乘 C win
3.普通情况 K win
通过枚举判断

代码:

var num,i,j:longint;
    ans,n,t:int64;
begin
  assign(input,'num.in');
  assign(output,'num.out');
  reset(input);
  rewrite(output);
  read(n);
  t:=n;
  for i:=2 to trunc(sqrt(n)) do
    while n mod i=0 do
    begin
      n:=n div i;
      inc(num);
    end;
  n:=t;
  if num=0 then
  begin
    writeln(1);
    writeln(0);
  end else
  if num=1 then writeln(2) else
  begin
    ans:=1;
    for i:=2 to trunc(sqrt(n)) do
    begin
      j:=0;
      while n mod i=0 do
      begin
        inc(j);
        ans:=ans*i;
        n:=n div i;
        if ans<>i then
        begin
          writeln(1);
          writeln(ans);
          close(input);
          close(output);
          halt;
        end;
      end;
    end;
  end;
  close(input);
  close(output);
end.

T3

题目描述:

月球上反凤凰装甲在凤凰之力附身霍普之前,将凤凰之力打成五份,分别附身在X战警五大战力上面辐射眼、白皇后、钢力士、秘客和纳摩上(好尴尬,汗)。

在凤凰五使徒的至高的力量的威胁下,复仇者被迫逃到昆仑的一座山上,因为凤凰五使徒监视不到那里。
霍普加入了复仇者,为了磨练自己,她在n个山峰之间跳跃。
这n个山峰在一条直线上,每个山峰都有不同的高度,只知道这些山峰的相对位置。霍普可以将这些山峰左右移动但不能改变他们的相对位置(要保证两两山峰间距为整数且大于等于1)。霍普要从最矮的山峰开始跳,每次跳向第一个比现在她所在的山峰高的山峰,一共跳n-1次,由于能力有限,每次跳跃的水平距离小于等于d。
霍普想知道如何移动这些山峰,使得在可以经过所有的山峰并跳到最高的山峰上的基础下,又要使最矮的山峰和最高的山峰的水平距离最远,霍普要你求出最远的水平距离。如果无论如何也不能经过所有的山峰并跳到最高的山峰上,那么输出-1。

思路:

排序+spfa
1.两个山峰距离>=1
2.霍普每次最多跳d的水平距离
对于第一个条件,对于两个相邻的山峰,相对位置(即输入顺序)大的向相对位置小的连条-1的边。 
对于第二个条件,对于两个高度排名相邻的山峰,相对位置小的向相对位置大的连一条d的边。 
然后比较最高和最低的山峰,从相对位置小的那个山峰出发,跑一遍SPFA最短路,输出到相对位置大的山峰的距离。

代码:

var s,t,w,next:array [0..5001] of longint;
    list,sum,dis:array [0..1001] of longint;
    a:array [0..1001,1..2] of longint;
    c:array [0..10000001] of longint;
    v:array [0..1001] of boolean;
    i,j,k,p,g,n,d:longint;
procedure spfa;
var head,tail,i,j:longint;
begin
  if a[1,2]>a[n,2] then
  begin
    j:=a[1,2];
    a[1,2]:=a[n,2];
    a[n,2]:=j;
  end;
  c[1]:=a[1,2];
  dis[a[1,2]]:=0;
  sum[a[1,2]]:=1;
  v[a[1,2]]:=true;
  head:=0;
  tail:=1;
  while head<tail do
  begin
    inc(head);
    i:=list[c[head]];
    while i>0 do
    begin
      if dis[s[i]]+w[i]<dis[t[i]] then
      begin
        dis[t[i]]:=dis[s[i]]+w[i];
        sum[t[i]]:=sum[t[i]]+1;
        if sum[t[i]]<n then
          if not(v[t[i]]) then
          begin
            v[t[i]]:=true;
            inc(tail);
            c[tail]:=t[i];
          end;
      end;
      i:=next[i];
    end;
    v[c[head]]:=false;
  end;
  if (dis[a[n,2]]>0) and (dis[a[n,2]]<>10000001) then writeln(dis[a[n,2]])
  else writeln(-1);
end;
procedure qsort(l,r:longint);
var i,j,mid:longint;
begin
  if l>=r then exit;
  mid:=a[(l+r) div 2,1];
  i:=l; j:=r;
  repeat
    while a[i,1]<mid do inc(i);
    while a[j,1]>mid do dec(j);
    if i<=j then
    begin
      a[0,1]:=a[i,1];a[i,1]:=a[j,1];a[j,1]:=a[0,1];
      a[0,2]:=a[i,2];a[i,2]:=a[j,2];a[j,2]:=a[0,2];
      inc(i); dec(j);
    end;
  until i>j;
  qsort(i,r);
  qsort(l,j);
end;
procedure main;
begin
  read(g);
  for k:=1 to g do
  begin
    fillchar(list,sizeof(list),0);
    fillchar(next,sizeof(next),0);
    fillchar(sum,sizeof(sum),0);
    fillchar(v,sizeof(v),false);
    p:=0;
    read(n,d);
    for i:=1 to n do
    begin
      read(a[i,1]);
      a[i,2]:=i;
      dis[i]:=10000001;
    end;
    qsort(1,n);
    for i:=1 to n-1 do
    begin
      inc(p);
      s[p]:=i+1;t[p]:=i;w[p]:=-1;
      next[p]:=list[s[p]];
      list[s[p]]:=p;
      inc(p);
      if a[i,2]>a[i+1,2] then
      begin
        s[p]:=a[i+1,2];
        t[p]:=a[i,2];
        w[p]:=d;
        next[p]:=list[s[p]];
        list[s[p]]:=p;
      end else
      begin
        s[p]:=a[i,2];
        t[p]:=a[i+1,2];
        w[p]:=d;
        next[p]:=list[s[p]];
        list[s[p]]:=p;
      end;
    end;
    spfa;
  end;
end;
begin
  assign(input,'attack.in');
  assign(output,'attack.out');
  reset(input);
  rewrite(output);
  main;
  close(input);
  close(output);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值