2016.08.15【初中部 NOIP提高组 】模拟赛C题解

    xiaoxiao2025-10-26  5

    这次的比赛实在是太水沝淼㵘了,前两题完全是来送分的(然而我第一题特么0分)

    T1

    这题是最水也是最容易被坑的(比如我)。。。

    Easy的字符串处理,之后模拟加减法就AC了

    K=0的情况:

    我们先把两个时间比较一下,如果第一个时间比第二个大,就说明已经经过了一天,就要把第二个时间加上24个小时,然后把两个时间相减,就是时减时,分减分,秒减秒,如果减出了负数就向前一位借位,然后再把时*3600+分*60+秒输出就可以了。

    K=1的情况:

    我们用模拟加法来解决这个问题。首先先把秒加上len,之后如果秒大于等于60则向前进位,之后分也向时进位,如果时大于等于24就直接mod 24就可以了,最后在判断一下,如果输出的某一项不足两位数就在前面输出一个0。

    T2

    水的不能再水的DP。。。

    我们只要先建一个数组a[1..2,1..3],值为(2,3),(1,3),(1,2)表示除了自己所在列外的另外两列。

    之后我们在建一个数组f[i,j],表示第i行选择第j种地铁的最低成本。

    因为当前列不能和上一列相同,所以得到这样一个状态转移方程:

    f[i,j]=min(f[i-1,a[j,1]],f[i-1,a[j,2]])+d[i,j](d是输入的数据)

    T3

    这道题我们可以先用拓扑排序先删除掉没有入度的节点,剩下的都是已经成环的。

    然后计算每一个环的结果,把每一个环中的所有节点都更改为这个结果。

    再计算那些没有成环的节点,最后输出答案就帅(wei)气(suo)的AC了

    提示:有一些坑(ri)爹(gou)的数据,a[i]=0且f[i]=i,这样会造成死循环,例如这组数据:

    2

    1 0

    2 2

    如果这组数据卡住了就说明出现了这种情况,我们只需要再判断一下就可以了。

    鉴于某些同学的要求,我把代码发上来吧。。。

    var         a:array[1..200000] of longint;         f:array[1..200000] of longint;         b:array[1..200000] of longint;         bz:array[1..200000]of boolean;         c:array[1..200000] of longint;         n,i,j,k,l:longint;         pd:boolean; begin         readln(n);         for i:=1 to n do         read(a[i]);         for i:=1 to n do         begin                 read(f[i]);                 inc(c[f[i]]);         end;         pd:=true;         while pd=true do         begin                 pd:=false;                 for i:=1 to n do                 if c[i]=0 then                 begin                         c[i]:=9999999;                         dec(c[f[i]]);                         pd:=true;                 end;         end;         for i:=1 to n do         if (bz[i]=false) and (c[i]<999999) then         begin                 j:=f[i];                 bz[i]:=true;                 k:=a[i];                 while bz[j]=false do                 begin                         bz[j]:=true;                         k:=k+a[j];                         j:=f[j];                 end;                 j:=f[i];                 b[i]:=k;                 while j<>i do                 begin                         b[j]:=k;                         j:=f[j];                 end;         end;         for i:=1 to n do         if b[i]=0 then         begin                 j:=i;                 while (b[j]=0) and not((j=f[j]) and (a[j]=0)) do                 begin                         b[i]:=b[i]+a[j];                         j:=f[j];                 end;                 if i<>j then                 b[i]:=b[i]+b[j];         end;         for i:=1 to n do         writeln(b[i]); end. 

    仅供参考,谢绝抄袭

    T4

    这道题直接暴力BFS就可以AC了。。。

    我们定一个循环队列D,然后把d[1]设为输入的n。

    再定一个B数组,b[i]表示从状态n经过操作后变成状态i所需的最小步数。

    先把b数组初始化,再把b[n]设为0。

    之后对于每种情况进行三种操作。

    第一种:

    我们只要二重循环枚举交换的位置,之后把两个数字交换。

    第二种:

    先判断一下当前字符串的长度是否大于1,然后在枚举删除的数的位置。

    第三种:

    先判断当前字符串长度是否小于初始长度,然后先把字符串转成数字,再放在数组里。之后枚举i、j,i表示当前从那个位置插入数字,j表示当前插入的数字。i从1~l-1(l表示当前字符串的长度),j从当前位数字+1~下一位数字-1,用insert(chr(j+48),s,i+1)(注意一定是+1,因为要想插入到第一个数的后面就一定要插入到第二个位置)插入字符。

    每次操作时都先把原数转成字符串,操作完后再转回数字。

    最后在根据输入输出答案,如果当前的结果为b数组的初始值,就代表不能产生该结果,就直接输出-1。

    最后提示:由于s<100000,而且s不能包含0,所以s最多只有100000-1,b数组开到99999就可以了。

    真·最后提示:循环队列不要开的太小,要开到一百万左右,不会爆空间。

    看在我这么辛苦打字的份上,顶一个吧!

    转载请注明原文地址: https://ju.6miu.com/read-1303532.html
    最新回复(0)