2014-9-13 NOIP模拟赛

NOIP2014模拟赛

——lwher

 

题目名

环上的游戏

舞蹈课

数位和乘积

源文件

cycle.cpp/c/pas

dancingLessons.pas/cpp

digit.cpp.cpp/c/pas

输入文件

cycle.in

dancingLessons.in

digit.in

输出文件

cycle.out

dancingLessons.out

digit.out

时间限制

1000MS

1000MS

1000MS

内存限制

128MB

256MB

256MB

测试点

10

10

10

测试点分值

10

10

10

 

 

 

环上的游戏(cycle)

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

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

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

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

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

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

 

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

 

【输入格式】

第一行一个整数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

最后取到数的人获胜

/*
    没找出必败态的判断条件,就打了个暴力
*/
#include<iostream>
#include<cstdio>
using namespace std;
#define maxn 30
int n,a[maxn],ans;
void dfs(int pos,int k){
    if(ans)return;//存在必胜态 
    bool flag=0;
    if(a[pos]!=0){//可以走顺时针方向 
        a[pos]--;
        flag=1;
        dfs((pos+1)%n,!k);
        a[pos]++;
    }
    if(a[(pos-1+n)%n]!=0){//可以走逆时针方向 
        a[(pos-1+n)%n]--;
        flag=1;
        dfs((pos-1+n)%n,!k);
        a[(pos-1+n)%n]++;
    }
    if(!flag&&k==0){
        ans=1;
        return;
    }
}
int main(){
    freopen("cycle.in","r",stdin);
    freopen("cycle.out","w",stdout);
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i%n]);
    dfs(0,1);
    if(ans){
        printf("YES");
    }
    else{
        printf("NO");
    }
}
70分 暴力
/*
    本题由于至少存在一个0,所以其实就是考虑一条链的情况

    然后可以得出一个显然的结论,如果取一条边,那么一定要将它的权变为0,然后按链长的奇偶得出答案即可
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<set>
#include<queue>
#include<map>
#define pa pair<int,int>
#define inf 1000000000
#define ll long long 
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,l,r;
int a[50];
int main()
{
    //freopen("cycle.in","r",stdin);
    //freopen("cycle.out","w",stdout);
    n=read();r=n;
    for(int i=1;i<=n;i++)a[i]=read();
    while(a[l+1])l++;
    while(a[r])r--;
    r=n-r;
    if(l&1||r&1)puts("YES");
    else puts("NO");
    return 0;
}
100分

舞蹈课(dancingLessons)

问题描述

有n个人参加一个舞蹈课。每个人的舞蹈技术由整数来决定。在舞蹈课的开始,他们从左到右站成一排。当这一排中至少有一对相邻的异性时,舞蹈技术相差最小的那一对会出列并开始跳舞。如果相差最小的不止一对,那么最左边的那一对出列。一对异性出列之后,队伍中的空白按原顺序补上(即:若队伍为ABCD,那么BC出列之后队伍变为AD)。舞蹈技术相差最小即是的绝对值最小。

你的任务是,模拟以上过程,确定跳舞的配对及顺序。

输入

第一行为正整数:队伍中的人数。下一行包含n个字符B或者G,B代表男,G代表女。下一行为n个整数。所有信息按照从左到右的顺序给出。在50%的数据中,。

输出

第一行:出列的总对数k。接下来输出k行,每行是两个整数。按跳舞顺序输出,两个整数代表这一对舞伴的编号(按输入顺序从左往右1至n编号)。请先输出较小的整数,再输出较大的整数。

样例输入

4

BGBG

4 2 4 3

样例输出

2

3 4

1 2

样例输入

4

BGBB

1 1 2 3

样例输出

1

1 2

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<set>
#include<queue>
#include<map>
#define inf 1000000000
#define ll long long 
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,ans;
int a[200005],nxt[200005],pre[200005],a1[200005],a2[200005];
char ch[200005];
bool mark[200005];
struct data{int val,pos;};
inline bool operator>(data a,data b)
{
    return a.val>b.val||(a.val==b.val&&a.pos>b.pos);
}
void solve()
{
    priority_queue<data,vector<data>,greater<data> >q;
    for(int i=1;i<n;i++)
        if(ch[i]!=ch[i+1])
            q.push((data){abs(a[i]-a[i+1]),i});
    while(!q.empty())
    {
        int mn=q.top().val,now=q.top().pos;q.pop();
        int l=pre[now],t=nxt[now],r=nxt[t];
        if(mark[now]||mark[t])continue;
        if(abs(a[now]-a[t])!=mn||ch[now]==ch[t])continue;
        mark[now]=mark[t]=1;
        a1[++ans]=now;a2[ans]=t;
        if(l&&r&&ch[r]!=ch[l])
        {
            q.push((data){abs(a[r]-a[l]),l});
        }
        nxt[l]=r;pre[r]=l;
    }
    printf("%d\n",ans);
    for(int i=1;i<=ans;i++)
        printf("%d %d\n",a1[i],a2[i]);
}
int main()
{
    //freopen("dancingLessons.in","r",stdin);
    //freopen("dancingLessons.out","w",stdout);
    n=read();mark[0]=1;
    scanf("%s",ch+1);
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<n;i++)nxt[i]=i+1;
    for(int i=2;i<=n;i++)pre[i]=i-1;
    solve();
    return 0;
}
100分 小根堆+链表

数位和乘积(digit.cpp/c/pas)

【题目描述】

一个数字的数位和乘积为其各位数字的乘积。求所有的N位数中有多少个数的数位和乘积恰好为K。请注意,这里的N位数是可以有前导零的。比如01,02视为二位数,但是他们的数位和乘积都是0。

 

【输入格式】

一行两个整数N,K

 

【输出格式】

一个行一个整数表示结果。

 

【样例输入】

2 3

【样例输出】

2

【样例输入2】

2 0

【样例输出2】

19

 

【数据范围】

对于20%:N <= 6。

对于50%:N<=16

存在另外30%:K=0。

对于100%:N  <= 50,0 <= K <= 10^9。

#include<iostream>
#include<cstdio>
using namespace std;
int n,k,a[60],cnt;
int dfs(int pos){
    if(pos==n+1){
        int now=1;
        for(int i=1;i<=n;i++)
            now*=a[i];
        if(now==k)return 1;
        return 0;
    }
    int ans=0;
    for(int i=0;i<=9;i++){
        a[++cnt]=i;
        ans+=dfs(pos+1);
        cnt--;
    }
    return ans;
}
int main(){
    //freopen("Cola.txt","r",stdin);
    freopen("digit.in","r",stdin);
    freopen("digit.out","w",stdout);
    scanf("%d%d",&n,&k);
    printf("%d",dfs(1));
}
20分 暴力

 

posted @ 2017-08-23 10:15  Echo宝贝儿  阅读(159)  评论(0编辑  收藏  举报