2018研究生推免上机考试

区间内的真正素数

考察点:

  • 素数筛选(埃式筛法如下):

void get_prime(){
    is_prime[0] = is_prime[1] = 0;
    for(int i=2; i<max_n; i++){  
        if(!is_prime[i]) continue;
        for(int j=i*i; j<max_n; j+=i)
            is_prime[j] = 0;
    }
}
  • 数的转置:
int reverse_num(int x){
    int res = 0;
    do{
        res = res*10 + x%10;
        x/=10;
    }while(x!=0);
    return res;
}

简单密码:

考察点

  • 带空格字符串的输入:
#include <iostream>
using namespace std;

int main(){
    string s;
    while(getline(cin, s)){   //cin 在前
        cout << s << endl;
    }
}

拯救公主

考察点:广搜

  • 搜索空间:(x,y,v)
  • 状态扩展规则
    • 移动规则:上下左右移动, 时间加一。
    • 跳跃规则:按能量跳跃,跳出墙了落在靠墙的地方,且时间不变。
    • 可以选择跳也可以不跳。
  • 有效状态:
    • 不出墙
    • 跳跃后不是陷阱
  • 标记:三维flag标记
  • 有效状态数:max_n * max_n * max_v

最佳加法表达式

考察点:

  • 动态规划:

    • 状态:dp[i][j]:前j个数字放i个加号所能达到最小值。
    • 目标:dp[m][n]
    • 状态转移: 令dp[i][j]的最后一个加号放在第k个数字后。循环考察所有可能的k。我们有 dp[i][j] = min({dp[i-1][k] + num(k+1,j) | k = 1…j-1}).
    • 初态
      • dp[0][i], i=1…length = num(1,i).
      • dp[i][j] = inf.(不可达状态)i>=j.(这个可以在循环过程中在赋值)
    • 状态转移示意图:
      在这里插入图片描述
      可以看到,状态转移始终只依赖于左上角部分,因此可以采用行优先遍历更新
  • 大数实现:
    首先先了解java对象赋值
    java大数类常用操作
    第一次做此类题,贴完整代码


import java.math.BigInteger;
import java.util.*;

public class Main{
	
	public static void main(String[] args){
		int m;
		BigInteger number;
		final int max_n = 80;
		BigInteger inf = new BigInteger("9999999999999999999999999999999999");
		Scanner cin = new Scanner(System.in);
		BigInteger[][] dp = new BigInteger[max_n][max_n];
		BigInteger tmp, mm;
		while(cin.hasNext()){
			m = cin.nextInt();
			number = cin.nextBigInteger();
			
			//初始化
			int length = number.toString().length();
		
			for(int i=1; i<=length; i++){
				dp[0][i] = new BigInteger(number.toString().substring(0, i));
			}
			dp[0][0] = inf;
			
			for(int i=1; i<=m; i++){
				for(int j=1; j<=length; j++){
					dp[i][j] = inf;
					if(i >= j)
						continue;
					mm = inf;
					for(int k=i; k<=j-1; k++){
						if(dp[i-1][k].equals(inf))
							continue;
						tmp = dp[i-1][k].add(new BigInteger(number.toString().substring(k, j)));
						dp[i][j] = dp[i][j].min(tmp);
					}
				}
			}
			
			System.out.println(dp[m][length]);
		}
		cin.close();
		
	}
	
}

热血格斗场

分析:由于每个人的战斗力不同,因此我们可以使用map做power2id的映射。
然后根据map.lower_bound来确定需要挑战的人。
知识点.

  • map配合lower_bound的使用,使用示意图如下
    在这里插入图片描述
  • 注意:迭代器不可以使用 pos+1/-1,只能使用pos++.
  • 引入<algorithm>
  • 声明迭代器map<int, int>:: iterator pos;
    第一次使用map+lower_bound():贴源码:
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
map<int, int> power2id;
map<int, int>::iterator pos1, pos2;

int main(){
    int n, id, power;
    cin >> n;

    power2id[100000] = 1;
    while(n--){
        cin >> id >> power;
        pos2 = power2id.lower_bound(power);

        if(pos2==power2id.begin()){
            cout << id << " " << (pos2)->second << endl;
        }
        else if(pos2 == power2id.end()){
            pos2--;
            cout << id << " " << (pos2)->second << endl;
        }
        else{
            pos1 = pos2;
            pos1--;
            if(pos2->first-power < power-pos1->first){
                cout << id << " " << pos2->second << endl;
            }
            else
                cout << id << " " << pos1->second << endl;
        }
        power2id[power] = id;
    }
    return 0;
}

Bug’s life

分析:满足带权并查集的问题求解条件,使用带权并查集,分析见此
代码:

#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std;

const int max_n = 2000+5;
int father[max_n];
int r[max_n];

void init(){
    memset(father, -1 ,sizeof(father));
    memset(r, 0, sizeof(r));
}

int find_father(int x){
    if(father[x] == -1) return x;
    int tmp = find_father(father[x]);
    r[x] = r[father[x]]^r[x]; // 与普通并查集区别,而且这里不能写反了!!!!!
    father[x] = tmp;
    return tmp;
}
int main(){
    int T;
    scanf("%d", &T);
    int n,m,a, b, fa, fb, flag;
    for(int i=1; i<=T; i++){
        init();
        flag = 1;
        scanf("%d%d", &n, &m);
        for(int j=0; j<m; j++){
            scanf("%d%d", &a, &b);
            if(!flag)
                continue;
            fa = find_father(a);
            fb = find_father(b);
            if(fa == fb){
                if(r[a] == r[b]){
                    flag = 0;
                }
            }
            else{
                r[fa] = (r[a]^1^r[b]); //与普通并查集区别!!
                father[fa] = fb;
            }
        }
        if(flag){
            printf("Scenario #%d:\nNo suspicious bugs found!\n\n", i);
        }
        else{
            printf("Scenario #%d:\nSuspicious bugs found!\n\n", i);
        }
    }
     return 0;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值