题目大意:给你n条路径构成一个无向树,结点编号为1~n。
在这棵树中,结点 1 为出口,其他所有结点上都有一只蝴蝶。
每一分钟,每只蝴蝶都会沿着一条树的边向 1 号结点方向移动。当蝴蝶到达1结点就代表它逃出了秘密花园 ,将永远消失不会被捕捉了。
主人公Bobo能做的是选择树中某一分钟的任何结点(包括第0分钟,所有的蝴蝶都在它们各自的结点上),并捕获该结点上的所有蝴蝶(Bobo不能捕获结点1上的蝴蝶,因为蝴蝶到达结点1后立即消失)。
求Bobo抓到所有的蝴蝶最少要操作几次。
实现思路:
cnt记录抓了几次。
1、第一次先抓所有下一分钟就飞到1结点的结点,就是抓1结点的邻接点。
cnt += 邻接点数
2、之后就等蝴蝶到达 1结点的邻接点的时候再抓就行,也就是抓的次数就是子树的高度。
总之,可以直接cnt+=临界子树的高度(此处定义为,只要有1个点都算高度1)就行。
ac代码:
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
const int N = 1e5 + 5;
int h[N], e[2*N], ne[2*N], idx;
bool vis[2*N];
void add(int from, int to){
e[idx] = to;
ne[idx] = h[from];
h[from] = idx ++;
}
long long bfs(int node, long long deep){
if(vis[node] || node == -1) return deep - 1;
else vis[node] = 1;
int initdeep = deep;
for(int i = h[node]; i != -1; i = ne[i]){
int j = e[i];
deep = max(deep, bfs(j, initdeep + 1));
}
return deep;
}
void solve(){
int n;
cin >> n;
memset(h, -1, sizeof h);
for(int i = 1; i <= n - 1; i ++){
int from, to;
cin >> from >> to;
add(from, to);
add(to, from);
}
long long ans = 0;
vis[1] = 1;
for(int i = h[1]; i != -1; i = ne[i]){
int j = e[i];
ans += bfs(j, 1);
}
cout << ans << endl;
}
int main(){
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
solve();
return 0;
}
题目大意:国王给穷人发食物。穷人站成一排。一个人获得食物的条件是他当前的permutaion值比左右两侧的人都小或者他只比两侧其中一个人的值小即可在本轮获得食物。当他获得食物后就不能参加下一轮发食物,本轮发完食物就离开队列。
当还剩下一个人的时候不算轮数。
求最小发食物的轮数。
实现思路:强行模拟即可。两个vector数组存当前状态和下一回合剩下哪些人,不断迭代。注意边界条件。
ac代码:
/*
5
1 2 3 4 5
5
1 5 3 4 2
2
1 2
*/
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
void solve(){
int n;
cin >> n;
vector<int> book(n);
for(int i = 0; i < n; i ++) {
cin >> book[i];
}
vector<int> tis;
int num = 0;
int left_num = n;
while(left_num > 1){
num ++;
tis = vector<int>();
for(int i = 0; i < book.size(); i ++) {
if(i == 0 && book[i] > book[i + 1]) tis.push_back(book[i]);
else if(i == n - 1 && book[i] > book[i - 1]) tis.push_back(book[i]);
else if(book[i] > book[i + 1] && book[i] > book[i - 1]) {
tis.push_back(book[i]);
}
}
left_num = tis.size();
book = tis;
}
cout << num << endl;
}
int main(){
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
solve();
return 0;
}
题目大意:构造题。读懂题目给的大量且繁杂的信息,根据题意去构造。我想到了肯定要构造一条直线,而且这条直线的生命随着长度变化而变长,但是想不到竟然是斜对角线构造的,而且代码短得和弱智一样。
实现思路:读入n,构造n=2*n-1个点,每个点的坐标都是(i,i)。
ac代码:
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
void solve(){
long long n;
cin >> n;
n = 2 * n - 1;
cout << n <<endl;
for(int i = 1 ; i <= n ; i ++) {
cout << i << " " << i << endl;
}
}
int main(){
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
solve();
return 0;
}
题目大意:石头剪刀布的游戏规则,给你一开始的一串石头剪刀布的排列,求他们两两比较,胜利的晋级下一轮,最终“胜利金字塔顶端的”是哪个赢?
s<=1e6
模拟直接超时
实现思路:怎么也想不到是单调栈。直接用s序列,单调栈遍历所有元素,最终栈底的那个手势就是最终的胜者。
ac代码:
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef pair<int, int> pii;
bool vic(char a, char b){
if(a == b) return false;
if(a == 'R' && b == 'P') return false;
if(a == 'P' && b == 'S') return false;
if(a == 'S' && b == 'R') return false;
return true;
}
void solve(){
string a;
cin >> a;
stack<char> sk;
for(int i = 0; i < a.size(); i ++) {
if(sk.empty()) {
sk.push(a[i]);
continue;
}
while(!sk.empty() && !vic(sk.top(), a[i])) {
sk.pop();
}
sk.push(a[i]);
}
while(sk.size() != 1) sk.pop();
cout << sk.top() << endl;
}
int main(){
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t;
cin >> t;
while(t--) solve();
return 0;
}