jzoj 模拟赛总结(2017.07.10)

本文解析了四个算法挑战赛题目,包括权势二进制、数字游戏、复仇者跳跃训练及未知第四题。针对每题提供了详细的题解思路及实现代码,帮助读者理解算法设计原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

T1.
权势二进制
题目大意:
给出K组数据,每组给出一个十进制整数N,做权势二进制是十进制表示的时候只由0或1组成。例如0,1,101,110011都是权势二进制而2,12,900不是。
当给定一个n的时候,计算一下最少要多少个权势二进制相加才能得到n。

1<=k<=10
1<=n<=1000000

题解:
对于一个N,我们发现只需要找到他某个最大的数字X然后输出就可以了,因为可以用X-1去将他抵消(抵消过程中其他同样被抵消),然后每一位都在0~1,就可以全抵掉。

时间复杂度:O(length(N))

var
     i,j,k,max:longint;
     n:string;
begin
     assign(input,'a.in'); reset(input);
     assign(output,'a.out');rewrite(output);
     readln(k);
     for i:=1 to k do
     begin
           readln(n);
           max:=0;
           for j:=1 to length(n) do
             if ord(n[j])-48>max then max:=ord(n[j])-48;
           writeln(max);
     end;
     close(input);close(output);
end.

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

对于30%的数据,Q<=50
对于100%的数据,Q<=10^13

题解:
分情况讨论:
对于Q:
1:质数,writeln(1); write(0);
2:两个质数的乘积(两个质数可以相等),write(2)
3:n=k*t*t, t为此质因数的积,枚举找到T输出

var
    i,num:longint;
    j,k,n,m,ans:int64;
begin
  assign(input,'num.in'); reset(input);
  assign(output,'num.out');rewrite(output);
    readln(n);
    m:=n;
    for i:=2 to trunc(sqrt(n)-0.1) do
      while n mod i=0 do
      begin
           n:=n div i;
           num:=num+1;
      end;

    if trunc(sqrt(n))=sqrt(n)
       then inc(num);

    n:=m;

    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
                            k:=0;
                            while n mod i=0 do
                            begin
                                 inc(k);
                                 n:=n div i;
                                 ans:=ans*i;
                                 if ans<>i then
                                 begin
                                     writeln(1);
                                     writeln(ans);
                                     halt;
                                     close(input); close(output);
                                 end;
                             end;
                        end;
                     end;
    close(input);close(output);
end.

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

题解:
差分约束系统:
把这道题目分解,可以分解为两个条件。
1、两个山峰之间水平距离至少为1(因为山峰不能再同一位置上)。
2、霍普每次最多跳d的水平距离。

对于第一个条件,对于两个相邻的山峰,相对位置(即输入顺序)大的向相对位置小的连一条-1的边。
对于第二个条件,对于两个高度排名相邻的山峰,相对位置小的向相对位置大的连一条d的边。
然后比较最高和最低的山峰,从相对位置小的那个山峰出发,做一次最短路,输出到相对位置大的山峰的距离。

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 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 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;

begin
     assign(input,'attack.in'); reset(input);
     assign(output,'attack.out');rewrite(output);
     readln(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;
          readln(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;
     close(input); close(output);
end.

T4.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值