emmmmm,渣渣侥幸入围国赛,最近开始入坑国赛题,慢慢啃吧。
1.【结果填空】 填算式
请看下面的算式:
(ABCD - EFGH) * XY = 900
每个字母代表一个0~9的数字,不同字母代表不同数字,首位不能为0。
比如,(5012 - 4987) * 36 就是一个解。
请找到另一个解,并提交该解中 ABCD 所代表的整数。
请严格按照格式,通过浏览器提交答案。
注意:只提交 ABCD 所代表的整数,不要写其它附加内容,比如:说明性的文字。
分析:简单暴力求解,蓝桥0-9的判断日常~
答案:6048
3.【结果填空】 埃及分数
古埃及曾经创造出灿烂的人类文明,他们的分数表示却很令人不解。古埃及喜欢把一个分数分解为类似: 1/a + 1/b 的格式。
这里,a 和 b 必须是不同的两个整数,分子必须为 1
比如,2/15 一共有 4 种不同的分解法(姑且称为埃及分解法):
1/8 + 1/120
1/9 + 1/45
1/10 + 1/30
1/12 + 1/20
那么, 2/45 一共有多少个不同的埃及分解呢(满足加法交换律的算同种分解)? 请直接提交该整数(千万不要提交详细的分解式!)。
请严格按照要求,通过浏览器提交答案。
注意:只提交分解的种类数,不要写其它附加内容,比如:说明性的文字
分析:暴力分数运算,采用结果2/45-op1=op2的判断方法,不同的分解则再判断下op1>op2.
答案: 7
4.【编程大题】 约数倍数选卡片
闲暇时,福尔摩斯和华生玩一个游戏:
在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资源约定:
峰值内存消耗(含虚拟机) < 64M
CPU消耗 < 2000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.6及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。
分析:蓝桥杯也超喜欢博弈论,尤其是结合递归模拟求解的那种,博弈论这块可能自己掌握的不够,一开始做的时候用的一维数组,本来想利用局部变量的性质进行求解,不过有点迷,我dfs的ArrayList参数在返回上一层的时候竟然改变了。。后来从大神博客中了解到用hash存卡牌数字出现的次数,用二位数组dfs…TAT(突然想放一张图:我离大佬就差那么一点.jpg】
Ps: 此题可以去蓝桥官网的评测系统去测试
Java代码:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
public class Main {
static ArrayList left = new ArrayList();
static ArrayList choose = new ArrayList();
static ArrayList[] select = new ArrayList[110];
static int[] cnt = new int[110]; //存1-100每个数字出现的次数
private static boolean dfs(int x) {
//返回当前这个人的输赢状态,x为上一个人(对手)上一局所选牌
for(int j = select[x].size()-1; j>=0; j--){ //倒序遍历,正序超时,参考了大神的代码...
int num = select[x].get(j);
if(cnt[num] > 0){
cnt[num]--;
boolean flag = dfs(num); //对于当前这个人来说,如果存在选完num后对方必败,则当前是必胜状态
cnt[num]++;
if(!flag) return true;
}
}
return false;
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String[] str1 = in.nextLine().split(" ");
String[] str2 = in.nextLine().split(" ");
for(int i = 0; iint num = Integer.parseInt(str1[i]);
left.add(num); //left存所有卡片
cnt[num]++;
}
for(int i = 0; iint num = Integer.parseInt(str2[i]);
choose.add(num); //choose存第一次可选卡片
}
for(int i = 1; i<101; i++){ //select为所有可选卡片,处理后为对应每一个数字,下一个可选数字
select[i] = new ArrayList();
if(cnt[i] == 0) continue;
for(int j = 1; j<101; j++){
if(i%j==0 || j%i==0){
select[i].add(j);
}
}
}
Collections.sort(choose);//排序后从小到大遍历,有满足条件的则输出
boolean flag = false;
for(int j = 0; jint x = choose.get(j);
cnt[x]--;
if(!dfs(x)){
flag = true;//找到一种必胜的牌即可退出
System.out.println(x);
break;
}
cnt[x]++;//否则还原现场
}
if(!flag) System.out.println(-1);
}
}
C++代码:
#include
using namespace std;
vector<int> lev,choose;
vector<int> total[110];
int ht[110];
bool dfs(int num){
bool flag = false;
for(int i = total[num].size()-1; i>=0; i--){
int x = total[num][i];
if(ht[x] > 0){
ht[x]--;
flag = dfs(x);
ht[x]++;
if(!flag) return true;
}
}
return false;
}
int main(){
string str1,str2;
getline(cin, str1);
getline(cin, str2);
int num = 0;
for(int i = 0; ichar ch = str1[i];
if(ch == ' '){
lev.push_back(num);
ht[num]++;
num = 0;
}
else if(i == str1.length()-1){
num = num*10+ch-'0';
ht[num]++;
lev.push_back(num);
}
else {
num = num*10+ch-'0';
}
}
num = 0;
for(int i = 0; ichar ch = str2[i];
if(ch == ' '){
choose.push_back(num);
num = 0;
}
else if(i == str2.length()-1){
num = num*10+ch-'0';
choose.push_back(num);
}
else {
num = num*10+ch-'0';
}
}
for(int i = 1; i<101; i++){
if(!ht[i]) continue;
for(int j = 1; j<101; j++){
if(i%j==0 || j%i==0){
if(ht[j]){
total[i].push_back(j);
}
}
}
}
sort(choose.begin(), choose.end());
for(int i = 0; iif(!dfs(num)){
cout<return 0;
}
ht[num]++;
}
cout<<-1<return 0;
}
5.【编程大题】 网络寻路
X 国的一个网络使用若干条线路连接若干个节点。节点间的通信是双向的。某重要数据包,为了安全起见,必须恰好被转发两次到达目的地。该包可能在任意一个节点产生,我们需要知道该网络中一共有多少种不同的转发路径。
源地址和目标地址可以相同,但中间节点必须不同。
如图1所示的网络。
1 -> 2 -> 3 -> 1 是允许的
1 -> 2 -> 1-> 2 或者 1->2->3->2 都是非法的。
输入数据的第一行为两个整数N M,分别表示节点个数和连接线路的条数(1<=N<=10000; 0<=M<=100000)。
接下去有M行,每行为两个整数 u 和 v,表示节点u 和 v 联通(1<=u,v<=N , u!=v)。
输入数据保证任意两点最多只有一条边连接,并且没有自己连自己的边,即不存在重边和自环。
输出一个整数,表示满足要求的路径条数。
例如:
用户输入:
3 3
1 2
2 3
1 3
则程序应该输出:
6
再例如:
用户输入:
4 4
1 2
2 3
3 1
1 4
则程序应该输出:
10
资源约定:
峰值内存消耗(含虚拟机) < 64M
CPU消耗 < 2000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.6及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。
分析:暴力dfs不重写输入流用Scanner在官网的评测系统能得80%的分,不过好像内存测评超过64M了…重写输入流才过,果然算法竞赛C++才是王道a
代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.ArrayList;
import java.util.Scanner;
public class Main {
static ArrayList[] arr = new ArrayList[10010];
static boolean[] vis;
static int m,n,u,v,cnt,st;
static void dfs(int cur, int step){
if(step == 3){
cnt++;
return;
}
for(int i = 0; iint tem = arr[cur].get(i);
if(tem == st && step!=2) continue;
if(!vis[tem]){
vis[tem] = true;
dfs(tem, step+1);
vis[tem] = false;
}
}
}
public static void main(String[] args) throws IOException {
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
in.nextToken();
n = (int)in.nval;
in.nextToken();
m = (int)in.nval;
for(int i = 1; i<=n; i++) arr[i] = new ArrayList<>();
for(int i = 0; iint)in.nval;
in.nextToken();
v = (int)in.nval;
arr[u].add(v);
arr[v].add(u);
}
for(int i = 1; i<=n; i++){
st=i;
vis = new boolean[n+10];
dfs(i, 0);
}
out.print(cnt);
out.flush();
}
}
有待更新…