区间内的真正素数
考察点:
- 素数筛选(埃式筛法如下):
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;
}