jzoj C组 2017.1.21

第一题——Sum the Square

题目描述

当你把一个正整数的各个数位平方之后相加,你会发现一些奇妙的现象,它出现了循环。比如说{5, 25, 29, 85, 89, 145, 42, 20, 4, 16, 37, 58, 89, …}。当然,说这个性质纯粹是为了好玩。为了多一些乐趣,这里给出两张图,这是两组平凡的数列:

这里写图片描述

现在,给定两个整数a1和b1,分别按照上述的方式构造数列{a1, a2, …, am}和{b1, b2, …, bn},其中am等于bn,你的目标是使得n+m最小。

输入

输入包含若干组数据,每组数据包含一行两个整数,分别为a1和b1。

输入0 0表示结束。

输出

每组数据输出一行,包含:a1,空格,b1,空格,n+m。

样例输入

89 89

19 100

61 19

0 0

样例输出

89 89 2

19 100 5

61 19 0

数据范围限制

【数据范围】 1<=A,B<=10^9

测试数据少于2000组


纯模拟,现将a的环求出来,然后再求B的环,如果当前b环的数也还A的环中,就判断该n+m是否比原来的小,则更新值。


代码如下:

var x,y,a,b,lx,ly,min:longint;
    fx,fy:array[0..1000]of longint;

function sq(x:longint):longint;
var  s:string;
     i:longint;
begin
  s:='';
  str(x,s);
  sq:=0;
  for i:=1 to length(s) do sq:=sq+sqr(ord(s[i])-48);
end;

begin
  assign(input,'square.in');
  assign(output,'square.out');
  reset(input);
  rewrite(output);  
  while 0=0 do
    begin
      readln(x,y);
      a:=x; b:=y;
      min:=maxlongint;
      lx:=0;
      ly:=0;
      fillchar(fx,sizeof(fx),#0);
      fillchar(fy,sizeof(fy),#0);
      if (x=0)and(y=0) then exit;
      if x=y then
        begin
          writeln(x,' ',y,' ',2);
          continue;
        end;
      if x>729 then
        begin
          x:=sq(x);
          inc(lx);
        end;
      if y>729 then
        begin
          y:=sq(y);
          inc(ly);
        end;
      while fx[x]=0 do
        begin
          inc(lx);
          fx[x]:=lx;
          x:=sq(x);
        end;
      while fy[y]=0 do
        begin
          inc(ly);
          if (fx[y]+ly<min)and(fx[y]>0) then min:=fx[y]+ly;
          fy[y]:=sq(y);
          y:=sq(y);
        end;
      if min=maxlongint then writeln(a,' ',b,' ',0)
                        else writeln(a,' ',b,' ',min);
    end;
  close(input);
  close(output);
end.

第二题——TheNumberGame

题目描述

Alice和Bob在玩一个游戏。游戏开始时,他们被给定一个整数。两个人轮流进行操作,每次操作时,玩家可以选取当前整数T的任意一个因子x,不包括1和T。然后将T-x交给下一名玩家。不能操作的玩家输。Alice先手。Alice和Bob都积极的进行游戏。你希望知道对于某些整数,谁会赢得游戏。

输入

数据包括若干组,每组数据包含一行一个整数,表示游戏开始时的整数。

输出

每组数据输出一行,Alice或Bob,表示胜者。

样例输入

2

3

6

样例输出

Bob

Bob

Alice

【样例说明】

当初始整数为2和3时,Alice无法操作,故Bob获胜。

当初始整数为6时,Alice可以选择3,使得Bob无法操作,故Alice胜。

数据范围限制

【数据范围】

对于30%的数据,输入整数<=10^5,数据少于100组

对于100%的数据,1<=输入整数<=10^18,数据少于1000组


找规律:①如果整数为奇数,则Bob赢
②如果整数是2的奇数次方,则Bob赢
③如果都不满足上面的两种情况,则Alice赢


代码如下:

var   i:longint;
      n:qword;
      f:boolean;
      a:array[1..32]of qword;
begin
  assign(input,'game.in');
  assign(output,'game.out');
  reset(input);
  rewrite(output);
  a[1]:=2;
  for i:=2 to 32 do a[i]:=a[i-1]*4;
  while not eoln do
    begin
      readln(n);
      f:=false;
      if n mod 2=1 then
        begin
          writeln('Bob');
        end
      else
        begin
          for i:=1 to 32 do
            if a[i]=n then begin writeln('Bob'); f:=true; break; end;
          if f=false then writeln('Alice');
        end;
    end;
  close(input);
  close(output);
end.

第三题——Mixing Chemicals

题目描述

实验室有n瓶化学药品,编号为0到n-1,你知道第i瓶只有和第c[i]瓶放在一起才会发生爆炸。为了整理实验室,你需要将他们装进k个不同的盒子里。显然,为了你的生命安全,你不能把两瓶会造成爆炸的药品放进同一个箱子。你希望计算出有多少中不同的方案。为了降低难度,你只需要将答案mod 1000000007。

输入

第一行一个整数T,表示有T组测试数据。

对于每组数据

第一行两个整数n,k

第二行n个整数表示c[i]

输出

对于每组数据输出一行一个整数。

样例输入

3

3 3

1 2 0

4 3

1 2 0 0

3 2

1 2 0

样例输出

6

12

0

数据范围限制

【数据范围】

1<=T<=50

1<=n<=100

2<=k<=1000

0<=c i < n,i≠c[i]

对于30%的数据T,n,k<=50


终于将这鬼题AK了(多亏了林大犇)的指导。
我们可以将不能放在一起的瓶子,看成两个点连成一条边(这样就形成了几个环套树也就是连通块),可以填k种颜色。
然后我们求出每个点可以填涂的颜色的数量,设f[i,0/1]表示为第i个点,0为填除黑色外的颜色,1为填黑色。
dp式为 f[i,0]:=(f[i-1,1]* (k-1)+f[i-1,0]*(k-2)) mod mo; f[i,1]:=f[i-1,0] mod mo;
mo为要取摸的数
然后我们将每个点在哪个环求出来,在求出连通块的个数,然后ans:=ans* (f[lt,1]*k mod mo)mod mo; lt为当前循环的搜到的连通块的个数
最后 n:=n-z; for i:=1 to n do ans:=ans*(k-1) mod mo; writeln(ans); 求出将每个连通块的填颜色的个数相乘就求出ans,最后输出就好了。


代码如下:

const mo=1000000007;
var   t,i,n,k,w,j:longint;
      lt,ans,temp,z:int64;
      f:array[0..100,0..1]of int64;
      a,b:array[0..100]of longint;
begin
  assign(input,'mix.in');
  assign(output,'mix.out');
  reset(input);
  rewrite(output);
  readln(t);
  for j:=1 to t do
    begin
      fillchar(a,sizeof(a),#0);
      fillchar(b,sizeof(b),#0);
      readln(n,k);
      f[1,0]:=k-1;
      f[0,1]:=1;
      for i:=2 to n do
        begin
          f[i,0]:=(f[i-1,1]*(k-1)+f[i-1,0]*(k-2)) mod mo;
          f[i,1]:=f[i-1,0] mod mo;
        end;
      for i:=0 to n-1 do
        begin
          read(a[i]);
          b[i]:=233;
        end;
      z:=0;
      ans:=1;
      readln;
      for i:=0 to n-1 do
        if b[i]=233 then
          begin
            temp:=i;
            while b[temp]=233 do
              begin
                b[temp]:=i;
                temp:=a[temp];
              end;
            if b[temp]<>i then continue;
            lt:=0;
            w:=temp;
            repeat
              inc(lt);
              temp:=a[temp];
            until temp=w;
            ans:=ans*(f[lt,1]*k mod mo)mod mo;
            z:=z+lt;
          end;
      n:=n-z;
      for i:=1 to n do ans:=ans*(k-1) mod mo;
      writeln(ans);
    end;
  close(input);
  close(output);
end.

今天做提高模拟题,一大堆0分的人(当然也有我),正是欲哭无泪啊!
感觉以我现在的水平,做两万年都做不出来(没有大神的指导),我还是先回松山湖修炼修炼吧。

转载于:https://www.cnblogs.com/Comfortable/p/8412441.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值