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"); } }
/* 本题由于至少存在一个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; }
舞蹈课(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; }
数位和乘积(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)); }