测评会员优惠活动进行中 · 开通 VIP,有效期内测评不限次 VIP 优惠中 · 测评不限次 立即查看

A40909. 约数倍数选卡片问题描述闲暇时,福尔摩斯和华生玩一个游戏:在N张卡片上写有N个整数。两人轮流拿走一张卡片。要求下一个人拿的数字一定是前一个人拿的数字的约数或倍数。例如,某次福尔摩斯拿走的卡片上写着数字“6”,则接下来华生可以拿的数字包括:1,2,3, 6,12,18,24 ....当轮到某一方拿卡片时,没有满足要求的卡片可选,则该方为输方。请你利用计算机的优势计算一下,在已知所有卡片上的数字和可选…

填空题 困难

题目描述

约数倍数选卡片

问题描述

闲暇时,福尔摩斯和华生玩一个游戏:

在N张卡片上写有N个整数。两人轮流拿走一张卡片。要求下一个人拿的数字一定是前一个人拿的数字的约数或倍数。例如,某次福尔摩斯拿走的卡片上写着数字“6”,则接下来华生可以拿的数字包括:

1,2,3, 6,12,18,24 ....

当轮到某一方拿卡片时,没有满足要求的卡片可选,则该方为输方。

请你利用计算机的优势计算一下,在已知所有卡片上的数字和可选哪些数字的条件下,怎样选择才能保证必胜!

当选多个数字都可以必胜时,输出其中最小的数字。如果无论如何都会输,则输出-1。

输入格式

输入数据为2行。第一行是若干空格分开的整数(每个整数介于1~100间),表示当前剩余的所有卡片。

第二行也是若干空格分开的整数,表示可以选的数字。当然,第二行的数字必须完全包含在第一行的数字中。

输出格式

程序则输出必胜的招法!!

样例输入

2 3 6

3 6

样例输出

3

样例输入

1 2 2 3 3 4 5

3 4 5

样例输出

4

参考答案

#include <iostream> #include <cstring> #include <cstdio> #include <vector> #include <algorithm> using namespace std; const int MAXN = 105; //num数组用于存放第一行输入的每一个数的出现次数 aa数组用于存放第二行先手可以先出的牌数 int num[MAXN],aa[MAXN]; vector<int> vec[MAXN]; //vec[i]用于存放在1和100之间并且在num数组中出现过的i的约数或者倍数 int ind; bool Select(int k) { //这里必须要从vec[k].size()开始,如果从0开始会出现超时(这里不懂为啥超时。。。) for(int i=vec[k].size()-1;i>=0;--i) if(num[vec[k][i]]) { num[vec[k][i]]--; bool ok = Select(vec[k][i]); num[vec[k][i]]++; if(ok) return false; } return true; } int main() { int x; while(true) { cin >> x; num[x]++; char ch = getchar(); if(ch == '\n') break; } while(true) { cin >> x; aa[++ind] = x; char ch = getchar(); if(ch == '\n') break; } //对aa数组排序,因为如果先手有必胜态,题目要求的是输出能产生必胜态的最小的数字 sort(aa+1,aa+ind+1); //下面的循环两层必须都从1到100循环,因为不管是先手还是后手,拿到一张牌之后,都要依据vec来 //寻找此数的约数或是倍数。 for(int i=1;i<=100;++i) for(int j=1;j<=100;++j) if((i%j==0||j%i==0)&&num[j]) vec[i].push_back(j); for(int i=1;i<=ind;++i) { if(num[aa[i]]) { num[aa[i]]--; //此处表示先出首先出了aa[i]这张牌 //如果Select(aa[i])返回true,那么说明后手不管出了什么牌,都是必败的,那么此时就可以输出 //aa[i]并且结束程序 if(Select(aa[i])) { printf("%d\n",aa[i]); return 0; } num[aa[i]]++; //回溯 这里表示先出aa[i]是必败的,那么判断下一种情况 } } printf("-1\n"); return 0; }
上一题 下一题