2014-11-1 NOIP模拟赛2

时间:2022-12-17 10:30:04

一、题目概览

中文题目名称

连连看

取数

游戏

迎接仪式

英文题目名称

card

cycle

game

welcome

可执行文件名

card

cycle

game

welcome

输入文件名

card.in

cycle.in

game.in

welcome.in

输出文件名

card.out

cycle.out

game.out

welcome.out

每个测试点时限

1秒

1秒

1秒

1秒

测试点数目

10

10

10

10

每个测试点分值

10

10

10

10

比较方式

全文比较

全文比较

全文比较

全文比较

题目类型

传统

传统

传统

传统

二、提交源程序文件名

对于Pascal语言

card.pas

cycle.pas

game.pas

welcome.pas

对于C语言

card.c

cycle.c

game.c

welcome.c

对于C++语言

card.cpp

cycle.cpp

game.cpp

welcome.cpp

三、编译命令(不包含任何优化开关)

对于Pascal语言

fpc game.pas

fpc hide.pas

fpc sign.pas

fpc chessman.pas

对于C语言

gcc –o game game.c

gcc –o hide hide.c

Gcc –o sign sign.c

gcc –o chessman chessman.c

对于C++语言

g++-o game game.cpp

g++-o hide hide.cpp

g++ -o sign sign.cpp

g++ -o chessman chessman.cpp

四、运行内存限制

运行内存上限

256M

256M

256M

256M

注意事项:

1. 文件名(程序名和输入输出文件名)必须使用小写。

2. C/C++中函数main()的返回值类型必须是int,程序正常结束时的返回值必须是0。

3. 统一评测时采用的机器配置为:CPU 1.9GHz,内存512M,上述时限以此配置为准。

 

 

 

 

 

 

 

 

 

 

取数(cycle)

时间限制:1S

问题描述

    有一个取数的游戏。初始时,给出一个环,环上的每条边上都有一个非负整数。这些整数中至少有一个0。然后,将一枚硬币放在环上的一个节点上。两个玩家就是以这个放硬币的节点为起点开始这个游戏,两人轮流取数,取数的规则如下:

    (1)选择硬币左边或者右边的一条边,并且边上的数非0;

    (2)将这条边上的数减至任意一个非负整数(至少要有所减小);

    (3)将硬币移至边的另一端。

    如果轮到一个玩家走,这时硬币左右两边的边上的数值都是0,那么这个玩家就输了。

如下图,描述的是Alice和Bob两人的对弈过程,其中黑色节点表示硬币所在节点。结果图(d)中,轮到Bob走时,硬币两边的边上都是0,所以Alcie获胜。

(a)Alice              (b)Bob                    (c)Alice        (d)Bob

 

现在,你的任务就是根据给出的环、边上的数值以及起点(硬币所在位置),判断先走方是否有必胜的策略。

 

【输入格式】

    第一行一个整数N(N≤20),表示环上的节点数。

    第二行N个数,数值不超过30,依次表示N条边上的数值。硬币的起始位置在第一条边与最后一条边之间的节点上。

 

【输出格式】

    仅一行。若存在必胜策略,则输出“YES”,否则输出“NO”。

 

【样例】

    cycle.in                        cycle.out

    4                           YES

    2 5 3 0    

    cycle.in                        cycle.out

    3                           NO

    0 0 0

最后取到数的人获胜

2014-11-1 NOIP模拟赛22014-11-1 NOIP模拟赛2
/*
    本题由于至少存在一个0,所以其实就是考虑一条链的情况
    然后可以得出一个显然的结论,如果取一条边,那么一定要将它的权变为0,然后按链长的奇偶得出答案即可
*/
#include<iostream>
#include<cstdio>
using namespace std;
int a[100],n;
int main(){
    freopen("cycle.in","r",stdin);
    freopen("cycle.out","w",stdout);
    scanf("%d",&n);
    for(int i=1,j=n+1;i<=n;i++,j++)scanf("%d",&a[i]),a[j]=a[i];
    int l=n,r=n+1;
    if(a[n]==0)l=n+1;
    if(a[n+1]==0)r=n;
    if(l>r){
        printf("NO");
        return 0;
    }
    while(a[r+1])r++;
    while(a[l-1])l--;
    if((n-l+1)%2==0&&(r-n)%2==0){
        printf("NO");
        return 0;
    }
    else printf("YES");
    return 0;
}
100分

 

 

游戏(game

问题描述

windy学会了一种游戏。
  对于1到N这N个数字,都有唯一且不同的1到N的数字与之对应。
  最开始windy把数字按顺序1,2,3,……,N写一排在纸上。
  然后再在这一排下面写上它们对应的数字。
  然后又在新的一排下面写上它们对应的数字。
  如此反复,直到序列再次变为1,2,3,……,N。

  如:
    1 2 3 4 5 6
    对应的关系为
    1->2 2->3 3->1 4->5 5->4 6->6
  windy的操作如下


    1 2 3 4 5 6
  2 3 1 5 4 6
  3 1 2 4 5 6
  1 2 3 5 4 6
  2 3 1 4 5 6
  3 1 2 5 4 6
  1 2 3 4 5 6

  这时,我们就有若干排1到N的排列,上例中有7排。
  现在windy想知道,对于所有可能的对应关系,有多少种可能的排数。

输入

输入文件game.in包含一个整数,N。

输出

  输出文件game.out包含一个整数,可能的排数。

样例输入

  【输入样例一】
  3
  【输入样例二】
  10

样例输出

  【输出样例一】
  3
  【输出样例二】
  16

数据规模和约定
    30%的数据,满足 1 <= N <= 10 。
    100%的数据,满足 1 <= N <= 1000 。 、

 

 

 

 

迎接仪式(welcome

 

【问题描述】

LHX教主要来X市指导OI学习工作了。为了迎接教主,在一条道路旁,一群Orz教主er穿着文化衫站在道路两旁迎接教主,每件文化衫上都印着大字。一旁的Orzer依次摆出“欢迎欢迎欢迎欢迎……”的大字,但是领队突然发现,另一旁穿着“教”和“主”字文化衫的Orzer却不太和谐。

为了简单描述这个不和谐的队列,我们用“j”替代“教”,“z”替代“主”。而一个“j”与“z”组成的序列则可以描述当前的队列。为了让教主看得尽量舒服,你必须调整队列,使得“jz”子串尽量多。每次调整你可以交换任意位置上的两个人,也就是序列中任意位置上的两个字母。而因为教主马上就来了,时间仅够最多作K次调整(当然可以调整不满K次),所以这个问题交给了你。

 

【输入格式】

输入文件welcome.in的第1行包含2个正整数N与K,表示了序列长度与最多交换次数。

第2行包含了一个长度为N的字符串,字符串仅由字母“j”与字母“z”组成,描述了这个序列。

 

【输出格式】

  输出文件welcome.out仅包括一个非负整数,为调整最多K次后最后最多能出现多少个“jz”子串。

 

【样例输入】

  5 2

zzzjj

 

【样例输出】

  2

 

【样例说明】

第1次交换位置1上的z和位置4上的j,变为jzzzj;

第2次交换位置4上的z和位置5上的j,变为jzzjz

最后的串有2个“jz”子串。

 

【数据规模】

对于10%的数据,有N≤10;

对于30%的数据,有K≤10;

对于40%的数据,有N≤50;

对于100%的数据,有N≤500,K≤100

2014-11-1 NOIP模拟赛22014-11-1 NOIP模拟赛2
/*
    dp[i][j][k]表示至第i位为止调换了j个‘j’和k个‘z’所得到的‘jz’串的最大个数, 每次只考虑s[i]和s[i-1]即可,只有'jz''jj''zz''zj'四种情况
*/
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int dp[501][101][101],n,m,ans;
char s[501];
int main(){
    freopen("welcome.in","r",stdin);
    freopen("welcome.out","w",stdout);
    scanf("%d%d",&n,&m);
    scanf("%s",s+1);
    for(int i=0;i<=n;i++)
        for(int j=0;j<=m;j++)
            for(int k=0;k<=m;k++)
                dp[i][j][k]=-0x7fffffff;
    dp[0][0][0]=dp[1][0][0]=0;
    if (s[1]=='j')dp[1][1][0]=0;
    else dp[1][0][1]=0;
    for(int i=2;i<=n;i++){
        for(int j=0;j<=m;j++){
            for(int k=0;k<=m;k++){
                dp[i][j][k]=dp[i-1][j][k];
                if(s[i-1]=='j'&&s[i]=='z')dp[i][j][k]=max(dp[i][j][k],dp[i-2][j][k]+1);
                if(s[i-1]=='j'&&s[i]=='j'&&j)dp[i][j][k]=max(dp[i][j][k],dp[i-2][j-1][k]+1);
                if(s[i-1]=='z'&&s[i]=='z'&&k)dp[i][j][k]=max(dp[i][j][k],dp[i-2][j][k-1]+1);
                if(s[i-1]=='z'&&s[i]=='j'&&j&&k)dp[i][j][k]=max(dp[i][j][k],dp[i-2][j-1][k-1]+1);
                if(j==k)ans=max(ans,dp[i][j][k]);
            }
        }
    }
    printf("%d",ans);
}
100分 线性dp

 

 

 

连连看(card)

【问题描述】

 

有时大型游戏玩腻味了,小Z也会玩玩弱智级的小游戏,比如连连看。但小Z眼力不行,常常得分很低。于是,他找到了你,希望你能帮他找出一种获胜方案。

连连看的游戏规则很简单:玩家可以将 2 个相同图案的牌连接起来,连接线不多于 3 条线段,就可以成功将两个牌消除。将游戏界面上的牌全部消除掉,玩家就胜利了。

 

【输入】

 

输入文件card.in的第一行为两个正整数m和n,表示连连看游戏的矩阵大小。

接下来的m行,每行n个英文大写字母(为了计算方便,只用A~E五个字母),表示牌的种类,相同字母表示同种牌。

 

【输出】

 

输出文件card.out。

若能获胜,则输出共一行,包括m×n/2个英文大写字母,第i个字母表示第i次消除的牌的种类。若有多解,输出字典顺序最小的解。

若不能获胜,则输出共一行,包括字符串“Game over.”。

 

【输入输出样例1】

 

card.in

card.out

2 1

A

A

A

 

【输入输出样例2】

 

Card.in

card.out

2 1

A

B

Game over.

 

【限制】

 

100%的数据满足:m×n<=12