模拟赛的题目都选自以往真题,在官网真题练习中都能找到,有分数的加减乘除、插入和归并排序、树的BFS遍历以及求图的单源最短路径(除了距离最短还有其他标尺的那种),知识点考的真均匀。其中有三题都在书上看到过,但还是没拿到满分并且对着书也找不出自己写法错误的那种,害。看了一眼排名,前n页都是满分选手,我的83分是227名。
就是分数的加减乘除,15分,有浮点错误。
原题链接:甲级 1088
#include // 15分,有浮点错误
#include
using namespace std;
struct fraction{
long long up;
long long down;
};
long long gcd(long long a, long long b){
if(b == 0) return a;
else return gcd(b, a%b);
}
fraction reduct(fraction a){
// 对分数进行约分
if(a.down < 0){
a.down = abs(a.down);
a.up = -a.up;
}
if(a.up == 0) a.down = 1;
long long d = gcd(abs(a.up), a.down);
// 约分
a.up /= d;
a.down /= d;
return a;
}
void print(fraction a){
// 输出一个分数
// printf("print:%lld %lld\n", a.up, a.down);
if(a.up < 0){
printf("(-");
}
if(a.down == 1)
printf("%lld", abs(a.up));
else if(abs(a.up) > a.down){
printf("%lld %lld/%lld", abs(a.up)/a.down, abs(a.up)%a.down, a.down);
}
else{
printf("%lld/%lld", abs(a.up), a.down);
}
if(a.up < 0){
printf(")");
}
}
fraction add(fraction a, fraction b){
fraction ans;
ans.down = a.down*b.down;
ans.up = a.up*b.down + b.up*a.down;
ans = reduct(ans);
return ans;
}
fraction minu(fraction a, fraction b){
fraction ans;
ans.down = a.down*b.down;
ans.up = a.up*b.down - b.up*a.down;
ans = reduct(ans);
return ans;
}
fraction mul(fraction a, fraction b){
fraction ans;
ans.down = a.down*b.down;
ans.up = a.up*b.up;
ans = reduct(ans);
return ans;
}
fraction de(fraction a, fraction b){
fraction ans;
ans.down = a.down*b.up;
ans.up = a.up*b.down;
ans = reduct(ans);
return ans;
}
int main(){
fraction a, b;
scanf("%lld/%lld %lld/%lld", &a.up, &a.down, &b.up, &b.down);
a = reduct(a);
b = reduct(b);
fraction temp;
temp = add(a, b);
print(a);
printf(" + ");
print(b);
printf(" = ");
print(temp);
printf("\n");
temp = minu(a, b);
print(a);
printf(" - ");
print(b);
printf(" = ");
print(temp);
printf("\n");
temp = mul(a, b);
print(a);
printf(" * ");
print(b);
printf(" = ");
print(temp);
printf("\n");
temp = de(a, b);
print(a);
printf(" / ");
print(b);
printf(" = ");
print(temp);
printf("\n");
return 0;
}
考排序原理,时间也够,根据原理可以用sort偷懒,17分,也有错误,感觉是Merge那里的步长问题。
原题链接:甲级 1089
#include // 17分
#include
#include
using namespace std;
vector<int> initial, result, temp1, temp2;
int n;
bool isInsert(){
bool flag = false;
for(int i=1; i<=n; i++){
sort(temp1.begin(), temp1.begin()+i);
if(temp1 == result){
flag = true;
printf("Insertion Sort\n");
sort(temp1.begin(), temp1.begin()+i+1);
for(int i=0; i<n; i++){
printf("%d", temp1[i]);
if(i != n-1)
printf(" ");
else
printf("\n");
}
break;
}
}
return flag;
}
void isMerge(){
int i;
for(i=1; i<=n; i*=2){
for(int j=i; j<=n; j+=i){
sort(temp2.begin()+j-i, temp2.begin()+j);
}
if(temp2 == result){
i*=2;
if(i <= n){
for(int j=i; j<=n; j+=i){
sort(temp2.begin()+j-i, temp2.begin()+j);
}
}
else{
sort(temp2.begin(), temp2.end());
}
for(int i=0; i<n; i++){
printf("%d", temp2[i]);
if(i != n-1)
printf(" ");
else
printf("\n");
}
}
}
}
int main(){
scanf("%d", &n);
int x;
for(int i=0; i<n; i++){
scanf("%d", &x);
initial.push_back(x);
temp1.push_back(x);
temp2.push_back(x);
}
for(int i=0; i<n; i++){
scanf("%d", &x);
result.push_back(x);
}
bool flag;
flag = isInsert();
if(!flag){
// 不是插入排序,是合并排序
printf("Merge Sort\n");
isMerge();
}
return 0;
}
对树进行BFS,我爱BFS!
原题链接:甲级 1090
#include
#include
#include
using namespace std;
const int maxn = 100010;
struct node{
int id;
int height;
}root, temp;
vector<node> adj[maxn]; //存放每个结点的孩子
int n;
int maxHeight=-1, height, num = 0;
bool isQueue[maxn] = {false};
void BFS(node root){
queue<node> q;
q.push(root);
isQueue[root.id] = true;
while(!q.empty()){
node top = q.front();
q.pop(); //不要忘记弹出去
height = top.height;
if(height > maxHeight){
maxHeight = height;
num = 1;
}
else if(height == maxHeight){
num++;
}
for(int i=0; i<adj[top.id].size(); i++){
node child = adj[top.id][i];
if(!isQueue[child.id]){
child.height = top.height+1;
q.push(child);
isQueue[child.id] = true;
}
}
}
}
int main(){
scanf("%d", &n);
double p, r;
scanf("%lf%lf", &p, &r);
// printf("p:%.2f r:%.2f\n", p, r);
int father;
for(int i=0; i<n; i++){
//每个结点的双亲
scanf("%d", &father);
if(father == -1){
root.id = i; //根结点的编号
root.height = 0;
}
else{
temp.id = i;
adj[father].push_back(temp); // 注意关系
}
}
BFS(root);
// printf("%d %d\n", maxHeight, num);
r /= 100;
double ans = p;
for(int i=0; i<maxHeight; i++){
ans *= (1+r);
}
printf("%.2f %d", ans, num);
return 0;
}
注意四个要求的分别是满足什么条件的路径,最后找路径是通过DFS的,这题超时了拿了26分。
原题链接:甲级1087
#include
#include
#include
#include
using namespace std;
const int INF = 0x3fffffff;
const int maxn = 210;
map<int, string> its;
map<string, int> sti;
int n, m;
int matrix[maxn][maxn]; //存放边权
int w[maxn], weight[maxn]; //存放点权, 到每个点的最大点权
int d[maxn]; //存放起点到其他点的最短距离
bool vis[maxn] = {false}; //存放点是否加入集合信息
int num_route[maxn];
int goal; // 终点编号
void Dijkstra(int s){
fill(d, d+maxn, INF);
d[s] = 0; // 初始时只有起点在集合中
weight[s] = 0;
num_route[s] = 1; // 假设路线都只有一条
// 循环n遍
for(int i=0; i<n; i++){
// 找到d值最小的没有访问过的结点u
int u=-1, min = INF;
for(int i=0; i<n; i++){
if(!vis[i] && d[i] < min){
u = i;
min = d[i];
}
}
if(u == -1) return ; // 不连通
// 把该结点加入集合
vis[u] = true;
// 以该结点为中介优化与u相连的点到起点的最短距离
for(int i=0; i<n; i++){
if(!vis[i] && matrix[u][i]!=INF){
if(d[i] > d[u]+matrix[u][i]){
d[i] = d[u]+matrix[u][i]; //距离更新
weight[i] = weight[u]+w[i]; // 幸福值更新
num_route[i] = num_route[u]; //路线条数继承
}
else if(d[i] == d[u]+matrix[u][i]){
num_route[i] += num_route[u]; //路线累加
if(weight[i] < weight[u]+w[i]){
weight[i] = weight[u]+w[i]; // 距离一样选择点权更大的一条
}
}
}
}
}
}
int minHeight = INF;
vector<int> temp, ans;
// 找到符合条件的那条路径
void DFS(int s, int height, int happy, int cost){
if(happy > weight[goal] | cost > d[goal]) return ;
if(s == goal){
if(height < minHeight && happy == weight[goal] && cost == d[goal]){
minHeight = height ;
ans = temp;
}
}
for(int i=0; i<n; i++){
if(matrix[s][i] != INF){
temp.push_back(i);
DFS(i, height+1, happy+w[i], cost+matrix[s][i]);
temp.pop_back();
}
}
}
int main(){
string name;
cin>>n>>m>>name;
int id = 0; //城市点编号从0开始到n-1
its.insert(make_pair(id, name));
sti.insert(make_pair(name, id));
id++;
w[0] = 0;
for(int i=1; i<n; i++){
cin>>name>>w[i];
its.insert(make_pair(id, name));
sti.insert(make_pair(name, id));
if(name == "ROM"){
goal = id; //记录罗马的编号
}
id++;
}
string c1, c2;
int dis;
int id1, id2;
// 先把边权矩阵初始化为无穷大
fill(matrix[0], matrix[0]+maxn*maxn, INF);
for(int i=0; i<m; i++){
cin>>c1>>c2>>dis;
id1 = sti[c1];
id2 = sti[c2];
// 注意是无向边
matrix[id1][id2] = dis;
matrix[id2][id1] = dis;
}
Dijkstra(0); // 求单源最短路径
temp.push_back(0); //源点肯定要加入路线的
DFS(0, 0, 0, 0);
cout << num_route[goal] <<" " << d[goal] <<" "<< weight[goal] <<" "<< weight[goal]/minHeight << endl;
for(int i=0; i<ans.size(); i++){
cout << its[ans[i]];
if(i != ans.size()-1){
cout << "->";
}
}
return 0;
}
最后拿了93分,出了一个样例点超时外,其他的答案错误不知道原因,大概172名+,我也想要王者徽章555 。
这是一题字符串处理+判断素数的题目。本来想用筛法,但是空间不够,后来发现直接判断也没关系,这题可以拿到满分。
#include
#include
#include
#include
using namespace std;
//const int maxn = 100000010;
//bool isPrime[maxn] = {false};
vector<int> nums;
//void init(){
// // 筛法求素数
// fill(isPrime, isPrime+maxn, true);
// isPrime[0] = false;
// isPrime[1] = false;
// for(int i=2; i
// if(isPrime[i]){
// for(int j=i*2; j
// isPrime[j] = false;
// }
// }
// }
//}
bool isPrime(int x){
// bool flag = true;
if(x == 1 || x == 0) return false;
int xx = sqrt(x);
for(int i=2; i<=xx; i++){
if(x%i == 0){
return false;
}
}
return true;
}
int main(){
// init();
string str;
cin>>str;
int num = 0, len = str.length();
for(int i=len-1; i>=0; i--){
num = num + (str[i]-'0')*pow(10, len-i-1);
nums.push_back(num);
}
int j=0;
bool flag = true;
for(int i=nums.size()-1; i>=0; i--){
// cout << nums[i] << endl;
cout << str.substr(j++) << " ";
if(isPrime(nums[i])){
cout << "Yes" << endl;
}
else{
cout << "No" << endl;
flag = false;
}
}
if(flag){
cout << "All Prime!";
}
return 0;
}
这是一道模拟题,只拿到了20分,看没过的样例点是答案错误,直接模拟不会有超时的问题,答案错误真的很难找到错误在哪啊。
初始时给出两个数,然后不断地给出一个数,这个数不能和前面给出地数重复,并且必须是前面任意两个数之差,否则就失败。
#include // 20分
#include
#include
#include
using namespace std;
const int maxn = 100010;
bool isOK[maxn] = {false};
set<int> fail_set; // 失败数字集合
vector<int> fail; // 出现了会失败的数字
bool kickout[15] = {false}; // 淘汰玩家编号
int nums[1010][15]; // 每一轮各个玩家出的数字
int n, m; //玩家数,轮数
void solve(){
int x, y;
for(int i=1; i<=m; i++){
// 先检查一下是否所有玩家都淘汰
bool flag = true;
for(int j=1; j<=n; j++){
if(!kickout[j]) flag = false;
}
if(flag) break; // 都淘汰了,游戏结束
for(int j=1; j<=n; j++){
if(!kickout[j]){
// 只考虑没淘汰玩家的数字
x = nums[i][j]; //j号玩家在第i轮给出的数为x
if(!isOK[x]){
kickout[j] = true; // j号玩家淘汰
printf("Round #%d: %d is out.\n", i, j);
}
else{
isOK[x] = false; // 已经出现过了,加入不可以数字集合
fail_set.insert(x);
// 将该值和所有出现过的值做差,设为下一个玩家可以出的数字
for(int i=0; i<fail.size(); i++){
y = abs(x-fail[i]);
if(fail_set.find(y) == fail_set.end()){
// 不是重复的不可以出现的数字
isOK[y] = true;
}
}
fail.push_back(x);
}
}
}
}
}
vector<int> winners;
int main(){
int a, b; // 初始数字
scanf("%d%d", &a, &b);
fail_set.insert(a);
fail_set.insert(b);
fail.push_back(a);
fail.push_back(b);
isOK[abs(a-b)] = true;
scanf("%d%d", &n, &m);
int x;
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
scanf("%d", &nums[j][i]);
}
}
solve();
for(int i=1; i<=n; i++){
if(!kickout[i])
winners.push_back(i);
}
if(winners.size() != 0){
printf("Winner(s): ");
for(int i=0; i<winners.size(); i++){
printf("%d", winners[i]);
if(i != winners.size()-1)
printf(" ");
}
}
else{
printf("No winner.");
}
return 0;
}
/*
101 42
4 5
49 17 67 9 7
17 9 8 50 7
25 92 43 26 37
59 17 1 41 40
*/
这是一道图的搜索问题,几乎是图着色问题,因为地图着色是NPC问题(找不到多项式时间求解问题的算法,但是给定一个该问题的解,可以在多项式时间内验证该解的正确性,即NP Complete问题),我选择对图进行BFS,发现相邻点的颜色(这题是动物种类)相同,就返回false。
#include // 23分
#include
#include
#include
using namespace std;
const int maxn = 510;
struct node{
int species; // 该区域动物编号
vector<int> adj; // 邻接矩阵
}Node[maxn];
int n, r, k;
set<int> st;
bool inq[maxn] = {false};
bool BFS(int s){
fill(inq, inq+maxn, false);
queue<int> q;
q.push(s);
inq[s] = true;
while(!q.empty()){
int top = q.front();
int species = Node[top].species;
q.pop();
for(int i=0; i<Node[top].adj.size(); i++){
int v = Node[top].adj[i];
if(Node[v].species == species){// 写外面对了
return false;
}
if(inq[v] == false){
// if(Node[v].species == species){
// return false;
// }
inq[v] = true;
q.push(v);
}
}
}
return true;
}
int main(){
scanf("%d%d%d", &n, &r, &k);
int a, b;
for(int i=0; i<r; i++){
// 无向边
scanf("%d%d", &a, &b);
Node[a].adj.push_back(b);
Node[b].adj.push_back(a);
}
int m, x;
scanf("%d", &m);
for(int i=0; i<m; i++){
st.clear();
// for(int j=0; j
for(int j=1; j<=n; j++){
scanf("%d", &x);
Node[j].species = x;
st.insert(x);
}
if(st.size() < k){
printf("Error: Too few species.\n");
}
else if(st.size() > k){
printf("Error: Too many species.\n");
}
else{
// BFS
bool flag = BFS(1); // 编号从1开始
if(flag){
printf("Yes\n") ;
}
else{
printf("No\n");
}
}
}
}
/*
6 0 3
5
1 2 3 3 1 2
1 2 3 4 5 6
4 5 6 6 4 5
2 3 4 2 3 4
2 2 2 2 2 2
*/
这是一道排序思想题,我之前没有接触过。但是感觉也是模拟题。
因为内存不够,只能放下m个数,但是有n个数需要进行排序。
这题可以用优先队列很好的解决,队列中的存放结构体,结构体中不光有该数的值,还存该数属于第几轮。那么先按照轮数小的排序,再按照值小的排序。
#include
#include
#include
using namespace std;
const int maxn = 100010; //元素数
struct node{
int runs; //第几轮
int value; //元素值
}temp;
struct cmp{
bool operator()(const node& a, const node&b){
if(a.runs != b.runs){
return a.runs > b.runs;
}
else{
return a.value > b.value;
}
}
};
priority_queue<node, vector<node>, cmp> pq;
vector<int> result[maxn]; // 每一轮的元素数
vector<int> nums;
int n, m; // 元素个数,内存容量
void solve(){
int i=0;
while(pq.size() < m){
temp.runs = 1;
temp.value = nums[i++];
pq.push(temp);
}
for(; i<n; i++){
int data = nums[i];
// 满了,取头元素出去
node top = pq.top();
pq.pop();
result[top.runs].push_back(top.value);
temp.value = data;
if(data < top.value){
temp.runs = top.runs+1;
}
else{
temp.runs = top.runs;
}
pq.push(temp);
}
while(!pq.empty()){
node top = pq.top();
pq.pop();
result[top.runs].push_back(top.value);
}
}
int main(){
scanf("%d%d", &n, &m);
int x;
for(int i=0; i<n; i++){
scanf("%d", &x);
nums.push_back(x);
}
solve();
for(int i=1; i<maxn; i++){
if(result[i].size() == 0) break;
for(int j=0; j<result[i].size(); j++){
printf("%d", result[i][j]);
if(j != result[i].size()-1)
printf(" ");
else
printf("\n") ;
}
}
return 0;
}