2016.08.12【初中部 NOIP提高组 】模拟赛C

本文解析了NOIP2011模拟赛的四道题目,包括作弊的发牌者、跳舞、遥控车及旅行问题。通过详细的算法描述和参考程序,帮助读者理解并解决这些问题。

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

第一题:

题目描述:

https://61.142.113.109/senior/#main/show/2544

2544. 【NOIP2011模拟9.3】作弊的发牌者 (StandardIO)

  贝茜正在与她的N-1(2<= N <= 100)个朋友打牌。她们玩的牌一副为K(N<=K<=100,000,K 为N 的倍数)张。所有牌中,一共有M(M = K/N)张“好牌”,其余的K-M 张为“差牌”。贝茜是游戏的发牌者,很自然地,她想把所有好牌都留给自己。她热衷于
获胜,即使为此必须采取一些不正当的手段。
  在若干局游戏后,贝茜的朋友们开始怀疑贝茜在游戏中作弊,于是她们想了个对策:使用新的发牌规则。规则具体如下:
  1. 贝茜把牌堆的最上面一张发给她右边的奶牛;
  2. 每当贝茜发完一张牌,她都得将牌堆顶部接下来的P(1 <= P<= 10)张牌放到底部去(一般把这个操作称为切牌);
  3. 然后,贝茜对逆时针方向的下一头奶牛重复上述的操作;
  贝茜绝望地认为,她再也不可能获胜了,于是她找到了你,希望你告诉她,将好牌放在初始牌堆的哪些位置,能够确保它们在发完牌后全集中到她手里。顺带说明一下,我们把牌堆顶的牌定义为1 号牌,从上往下第二张定义为2号牌,依此类推。

Input

  第1 行: 3 个用空格隔开的整数:N、K,以及P

Output

  贝茜和她的某两个朋友在打一副总共是9 张的牌。她每发出一张牌后,都得在牌堆顶部取出两张放到堆底。

Sample Input

3 9 2

Sample Output

3

7

8

【数据范围】

  对于30%的数据,2 <= N <=4,N<=K<= 100
  对于100%的数据,2 <= N <=100,N<=K<= 100,000


模拟暴力加点优化就可以了吧,考试时调试了我半天,结果还是被坑了3个点委屈注意细节啊!


参考程序:

var    n,k,p,i,j,t,lenb,kk,q,l:longint;

       a,b,a2:array[0..1000000]of longint;

procedure kuaipai(l,r:longint);

var    i,j,mid,t:longint;

begin

       i:=l;j:=r;

       mid:=b[(l+r)div 2];

       repeat

                while b[i]<mid do inc(i);

                while b[j]>mid do dec(j);

                if i<=j then

                begin

                        t:=b[i];

                        b[i]:=b[j];

                        b[j]:=t;

                        inc(i);

                        dec(j);

                end;

       until i>j;

       if l<j then kuaipai(l,j);

       if i<r then kuaipai(i,r)

end;

begin

       readln(n,k,p);

       lenb:=0;

       for i:=1 to k do a[i]:=i;

       kk:=k;

       while lenb<k div n do

       begin

                i:=1;

                while i<=kk do

                begin

                        inc(t);

                        if t mod n=0 then

                        begin

                                inc(lenb);

                                b[lenb]:=a[i];

                                t:=0;

                        end;

                        a[i]:=0;

                        i:=i+p+1;

                end;

                if lenb=k div n then break;

                i:=i-p-1;

                l:=p-(kk-i);

                if l>0 then

                begin

                        q:=0;

                        for i:=1 to kk+10000 do

                        begin

                                if a[i]>0 then

                                begin

                                       inc(q);

                                       a[kk+q]:=a[i];

                                        a[i]:=0;

                                end;

                                if q=l thenbreak;

                        end;

                        kk:=kk+q;

                end;

                fillchar(a2,sizeof(a2),0);

                for i:=1 to kk do

                begin

                        if a[i]>0 then

                        begin

                                inc(a2[0]);

                                a2[a2[0]]:=a[i];

                        end;

                end;

                kk:=a2[0];

                a:=a2;

       end;

       lenb:=k div n;

       kuaipai(1,lenb);

       for i:=1 to lenb do writeln(b[i]);

end.



第二题:

题目描述:

https://61.142.113.109/senior/#main/show/2545

2545. 【NOIP2011模拟9.3】跳舞 (StandardIO)

  小明今天得到一个跳舞毯游戏程序Dance。游戏每次连续出N 个移动的“箭头”,箭头依次标号为1 到N,并且的相应的分数S[1..N]。如果你能“踏中”第i 号箭头,你将获得相应的分数S[i];否则将被扣除相应的分数。
  另外,游戏还有一个累计奖励机制:如果踏准次数累计达到T,并且是在踏中第i个箭头达到的,则将得到B[i]的奖励分数,累计也将清零,重新开始。
  例如:N=6,T=3,相应的S 和B 分别为{1,2,3,4,5,6}、{0,0,4,7,9,10},如果小明踏中所有箭头,则得分为:(1+2+3+4)+(4+5+6+10)=35
  小明是个Dance 高手,可以踏中他想踏中的任意一个箭头。但他发现,根据给定的N,T,S,B,踏中所有的箭头不一定能得最高分,小明很想知道最高能得多少分,你能帮助小明计算一下最多可得多少分吗?

Input

  第一行两个整数N 和T。
  第二行N 个整数,为S 的相应分数。
  第三行也有N 个整数,为B 的相应分数。

Output

  只一个整数,可得到的最高分数。

Sample Input

6 3

1 2 3 4 5 6

1 1 1 20 1 1

Sample Output

39

【数据范围】
  对于20%的数据0≤N,T≤100;
  对于100%的数据0≤N,T≤5000;
  S 和B 各有N 个数,所有分数为[0,10000]之间的整数。


 果断DP 

 for i:=1 to n do
        begin
                for j:=i downto 1 do
                        if j mod t=0 then
                                f[j]:=max(f[j]-s[i],f[j-1]+s[i]+b[i]) else
                                f[j]:=max(f[j]-s[i],f[j-1]+s[i]);
                f[0]:=f[0]-s[i];
        end;

其中f[i]表示踏中i个的最大得分


参考程序:

var    n,t,i,j:longint;

       f:array[0..5000]of longint;

       s,b:array[1..5000]of longint;

function max(x,y:longint):longint;

begin

       if x>y then exit(x) else exit(y);

end;

begin

       readln(n,t);

       for i:=1 to n do read(s[i]);

       for i:=1 to n do read(b[i]);

       for i:=1 to n do

       begin

                for j:=i downto 1 do

                        if j mod t=0 then

                               f[j]:=max(f[j]-s[i],f[j-1]+s[i]+b[i]) else

                               f[j]:=max(f[j]-s[i],f[j-1]+s[i]);

                f[0]:=f[0]-s[i];

       end;

       for i:=1 to n do f[0]:=max(f[0],f[i]);

       writeln(f[0]);

end.


第三题:

题目描述:

https://61.142.113.109/senior/#main/show/2546

2546. 【NOIP2011模拟9.3】遥控车 (StandardIO)

  平平带着韵韵来到了游乐园,看到了n 辆漂亮的遥控车,每辆车上都有一个唯一的名字name[i]。韵韵早就迫不及待地想玩名字是s 的遥控车。可是韵韵毕竟还小,她想象的名字可能是一辆车名字的前缀(也就是说能确定一个i,使s 是name[i]的前缀),这时她就能玩第i 辆车;或者是一个无中生有的名字,即s 不是任何一辆车名字的前缀,这时候她什么也不能玩。
  你需要完成下面的任务:
  1.韵韵想了m 个她想要的名字,请告诉她能玩多少次。
  2.由于管理员粗心的操作,导致每辆车的摆放位置都可能出现微小的差错,原来第i辆车现在的位置可能是i-1、i、i+1 中的任意一个(第1 辆车的位置不可能是0,第n辆车的位置不可能是n+1)。请你计算出共有多少种可能的排列。
  注:数据保证当s 是name[i]的前缀时,i 是唯一确定的。一辆车可以玩多次。

Input

  第一行是2 个正整数n、m。
  接下来n 行,每行1 个字符串name[i],表示第i 辆车的名字。接下来m 行,每行1 个字符串s,表示韵韵想要的名字。

Output

  第一行输出韵韵能玩的次数。第二行输出共有多少种可能的排列。

Sample Input

4 4

Abcd

DeF

AAa

aBccc

Ab

AA

AbC

aBcc

Sample Output

3

5

【数据规模】
  对于题目涉及到的字符串严格区分大小写,且长度小于255。
  对于20%的数据n≤10,m≤10;
  对于40%的数据n≤1000,m≤1000;
  对于100%的数据n≤10000,m≤10000。



第一问直接暴力加点优化就行了,二分也行,对于第二问,很明显发现类似于斐波拉切数列,就是第一个是1;第二个是2;后面每个就是前面两个数的和,但是要用高精度~


参考程序:

var    n,m,i,j,ans,bz,k,l,lenb,t:longint;

       s:string;

       a:array[1..10000]of string;

       b,c,d:array[1..10000]of longint;

       e:array[1..58,0..1000]of longint;

begin

       readln(n,m);

       for i:=1 to n do

       begin

               readln(a[i]);

                t:=ord(a[i][1])-64;

                inc(e[t,0]);

                e[t,e[t,0]]:=i;

       end;

       for i:=1 to m do

       begin

                readln(s);

                l:=length(s);

                t:=ord(s[1])-64;

                for j:=1 to e[t,0] do

                begin

                        for k:=1 to l do

                                ifa[e[t,j]][k]<>s[k] then break;

                        if a[e[t,j]][k]=s[k] then

                        begin

                               inc(ans);

                                break;

                        end;

                end;

       end;

       writeln(ans);

       lenb:=1;

       b[1]:=2;

       c[1]:=1;

       for i:=3 to n do

       begin

               fillchar(d,sizeof(d),0);

                for j:=1 to lenb do

                begin

                        d[j]:=b[j]+c[j]+d[j];

                        d[j+1]:=d[j] div 10;

                        d[j]:=d[j] mod 10;

                end;

               inc(lenb);

                if d[lenb]=0 then dec(lenb);

                c:=b;

                b:=d;

       end;

       for i:=lenb downto 1 do write(b[i]);

end.


第四题:

题目描述:

https://61.142.113.109/senior/#main/show/2547

2547. 【NOIP2011模拟9.3】旅行 (StandardIO)

Time Limits: 1000 ms  MemoryLimits: 256000 KB  Detailed Limits  

Description

  Z 小镇是一个景色宜人的地方,吸引来自各地的观光客来此旅游观光。Z 小镇附近共有N 个景点(编号为1,2,3,…,N),这些景点被M 条道路连接着,所有道路都是双向的,两个景点之间可能有多条道路。也许是为了保护该地的旅游资源,Z 小镇有个奇怪的规定,就是对于一条给定的公路Ri,任何在该公路上行驶的车辆速度必须为Vi。
  速度变化太快使得游客们很不舒服,因此从一个景点前往另一个景点的时候,大家都希望选择行使过程中最大速度和最小速度的比尽可能小的路线,也就是所谓最舒适的路线。

Input

  第一行包含两个正整数,N和M。
  接下来的M 行每行包含三个正整数:x,y 和v。表示景点x 到景点y 之间有一条双向公路,车辆必须以速度v 在该公路上行驶。
最后一行包含两个正整数s,t,表示想知道从景点s 到景点t 最大最小速度比最小的路径。s 和t 不可能相同。

Output

  如果景点s 到景点t 没有路径,输出“IMPOSSIBLE”。否则输出一个数,表示最小的速度比。如果需要,输出一个既约分数。

Sample Input

【样例输入1】

4 2

1 2 1

3 4 2

1 4

【样例输入2】

3 3

1 2 10

1 2 5

2 3 8

1 3

【样例输入3】

3 2

1 2 2

2 3 4

1 3

Sample Output

【样例输出1】

IMPOSSIBLE

【样例输出2】

5/4

【样例输出3】

2

【数据范围】
  对于100%的数据,1 < N≤500,1≤x,y≤N,0

 

这题要用到并查集,不会的可以查看http://blog.youkuaiyun.com/fengyingjie2/article/details/52192573

(这是转载某大神的~)


把边按照权值从小到大排好序之后,先是枚举从哪条边开始往下建图,再枚举现在建图用到了哪条边,则对于当前枚举到的边,判断其最老父亲是否相同,不同的话则把他们相连,再加上路径压缩,当连上第j条边时判断s到t是否能通,能通的话则直接判断答案是否需要更新,并直接Break...


参考代码:

var    n,m,s,t,i,j,ans1,ans2,p1,p2:longint;

       min:real;

       a:array[0..50000,1..3]of longint;

       father:array[0..500]of longint;

function gys(n,m:longint):longint;

begin

       if n mod m=0 then gys:=m

       else gys:=gys(m,n mod m);

end;

procedure kuaipai(l,r:longint);

var    i,j,mid:longint;

begin

       i:=l;j:=r;

       mid:=a[(l+r)div 2,3];

       repeat

                while a[i,3]<mid do inc(i);

                while a[j,3]>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;

       if l<j then kuaipai(l,j);

       if i<r then kuaipai(i,r)

end;

function getfather(x:longint):longint;

begin 

       if father[x]=0 then exit(x);

       father[x]:=getfather(father[x]);

       exit(father[x]);

end;

procedure bingchaji(x,y:longint);

var    fx,fy:longint;

begin

       fx:=getfather(x);

       fy:=getfather(y);

       if fx<>fy then

                father[fx]:=fy;

end;

begin

       readln(n,m);

       for i:=1 to m do

                readln(a[i,1],a[i,2],a[i,3]);

       readln(s,t);

       kuaipai(1,m);

       min:=maxlongint;

       for j:=1 to m do

       begin

                p1:=-maxlongint;

                p2:=maxlongint;

                fillchar(father,sizeof(father),0);

                for i:=j to m do

                begin

                        if a[i,3]>p1 then p1:=a[i,3];

                        if a[i,3]<p2 thenp2:=a[i,3];

                        if getfather(a[i,1])<>getfather(a[i,2])then

                        begin

                                bingchaji(a[i,1],a[i,2]);

                       end;

                        ifgetfather(s)=getfather(t) then

                                if min>p1/p2then

                                begin

                                       min:=p1/p2;

                                        ans1:=p1;

                                       ans2:=p2;

                                        break;

                                end;

                end;

       end;

       if (ans1=0)and(ans2=0)then

       begin

                writeln('IMPOSSIBLE');

                exit;

       end;

       if ans1 mod ans2=0 then

       begin

                writeln(ans1 div ans2);

                exit;

       end;

       t:=gys(ans1,ans2);

       ans1:=ans1 div t;

       ans2:=ans2 div t;

       writeln(ans1,'/',ans2);

end.

 





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值