A.Robin Helps
算法:模拟
按照题意模拟即可(数据范围很小)A-E
需要注意当先我手中有黄金时才可以给
C++代码
#include <bits/stdc++.h>
using namespace std;
const int N = 60;
int T,n,k;
void solve(){
cin >> n >> k;
int ans = 0, res = 0;
for(int i = 0; i < n; i++){
int x;
cin >> x;
if(x >= k) res += x;
else if(!x){ //当前ai = 0 ,那么给一个黄金
if(res >= 1) { //我手里有黄金时才能给
res--;
ans ++; //给黄金的人数
}
}
}
cout << ans << endl;
}
int main(){
cin >> T;
while(T--){
solve();
}
return 0;
}
B.Robin Hood and the Major Oak
算法: 数学
思路:
判断区间内奇数个数是否为偶数即可
分情况讨论:
(1)k >= n 时, 说明叶子能存活到第n年
用n % 4 来判断可行
比如:1 2 3 4
x x o o
因此,
string s = n % 4 == 3 || n % 4 == 0 ? "YES" : "NO";
(2) k < n时,用 k(寿命值来进行取模运算)
分两种情况来讨论:两种情况都是从后往前倒着看
1)第n年为奇数时,最后一年为奇数年
2 3 4 5
o o x x
2)第n年为偶数时,最后一年为偶数年
1 2 3 4
o x x o
C++代码
#include <bits/stdc++.h>
using namespace std;
int T,n,k;
void solve(){
cin >> n >> k;
string s = "";
if(k >= n){
//1 2 3 4 5
s = n % 4 == 3 || n % 4 == 0 ? "YES" : "NO" ;
}
//1 2 3 || 2 3 4 5
else if(n % 2 == 1) //n & 1
{
s = k % 4 == 1 || k % 4 == 2 ? "NO" : "YES";
}
//1 2 3 4
else{
s = k % 4 == 2 || k % 4 == 3 ? "NO" : "YES";
}
cout << s << endl;
}
int main(){
cin >> T;
while(T--){
solve();
}
return 0;
}
C.Robin Hood in Town
算法: 二分
思路:
1.理解题意
什么时候罗宾汉出现呢?
当且仅当**不快乐的人数**严格大于总人口数的一半的时候
什么是不快乐的人数?
一个人的财富**严格少于平均财富的一半**,那么这个人就是不快乐的人。
2.为何用二分?
1)满足单调性 2)求罗宾汉出现的最小的x
由于我们需要求的x的数是最小的,因此左向逼近
用l + r >> 1 板子即可
C++代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10;
int T,n,sum;
int a[N];
bool check(int x){
double ave = (sum + x) * 1.0 / (2.0 * n);
int cnt = 0; //不快乐的人数
for(int i = 1; i <= n; i++){
if(a[i] < ave) cnt ++;
}
return cnt > n / 2; //是否一半以上的人为不快乐的人
}
void solve(){
memset(a,0,sizeof a);
sum = 0;
cin >> n;
for(int i = 1; i <= n; i++){
cin >> a[i];
sum += a[i];
}
if(n <= 2) {
cout << "-1" << endl;
return;
}
int l = 0, r = 1e18;
while(l < r){
int mid = l + r >> 1; //找到最小的x;因此左向逼近
if(check(mid)) r = mid;
else l = mid + 1;
}
cout << l << endl; //最小的x值
}
signed main(){
cin >> T;
while(T--){
solve();
}
return 0;
}
D.Robert Hood and Mrs Hood
算法: 滑动窗口,双指针
详细写在注释当中
C++代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int T,n,d,k;
void solve()
{
cin >> n >> d >> k;
vector<int>in(n+1); //开始的天数
vector<int>out(n+1); //结束的天数
//输入k个任务的开始与结束时间
for(int i = 1; i <= k; i++){
int x,y;
cin >> x >> y;
in[x] ++;
out[y]++;
}
int cnt = 0; //区间内任务的个数
int bro = -1, mo = k + 1;
//区间内开始的工作数量
for(int i = 1; i < d; i++){
cnt += in[i];
}
int b = -1, m = -1;
for(int i = 1; i + d - 1 <= n; i ++){
cnt -= out[i - 1]; //当前区间内结束的任务个数
cnt += in[i + d - 1]; //往后移动区间是区间内增加的任务数
if(cnt > bro) {
bro = cnt;
b = i; //哥哥入住的日期
}
if(cnt < mo) {
mo = cnt;
m = i;
}
}
cout << b << " " << m << endl ;
}
int main(){
cin >> T;
while(T--){
solve();
}
return 0;
}
E. Rendez-vous de Marian et Robinsuan
算法: 最短路
思路:
边权都是正数,我们可以用dijkstra 堆优化算法,而且是个稀疏图我们可以用邻接表来存储每一条边
玛丽亚在起点,罗宾在终点
如果不考虑马我们跑两遍dijkstra,从起点跑一遍最短路,从终点跑一遍最短路,最后再枚举相遇点,取最小值;
由题意可知,骑马之后的所有时间点会减少一半。(读题的时候误解这一部分,以为只有下一个点的时间减少一半)
1.首先我们要明确骑马之后不用再走已经走过的路,这里可以用vis[]来标记访问情况
难点:
2.走路到骑马的转换关系:
我们再开一个数组标记该点处是否有马;
pair<int,pair<int,bool> > q;
//第一个数据存放的是距离,按照距离的大小进行从小到大进行排序的
//第二个数据存放的是该结点的编号
//第三个数据存放的是该点是否有马的情况
C++代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int>PII;
const int INF = 1e18;
int T,n,m,h;
void dijkstra(vector<vector<PII>>& g,vector<vector<int>>& dist,vector<bool>&hs,int start){
vector<vector<bool> > st(n+1,vector<bool>(2,false));
priority_queue<pair<int,pair<int,bool>>,vector<pair<int,pair<int,bool>>>,greater<pair<int,pair<int,bool>>>>q;
dist[start][0] = 0;
q.push(make_pair(0,make_pair(start,0)));
while(!q.empty()){
auto t = q.top();
q.pop();
int ver = t.second.first;
bool u = t.second.second;
bool horse = ( u || hs[ver]);
if(st[ver][horse]) continue;
st[ver][horse] = true;
for(auto [j,w] : g[ver]) //枚举所有ver结点的邻接点
{
int val = horse ? w / 2 : w; //当前是否再骑马
if(dist[j][horse] > dist[ver][u] + val){
dist[j][horse] = dist[ver][u] + val;
q.push({dist[j][horse],{j,horse}});
}
}
}
}
void solve(){
cin >> n >> m >> h;
vector <bool> hs(n + 1);
while(h--){
int x;
cin >> x;
hs[x] = true;
}
vector<vector<PII>> g(n+1);
while(m--){
int a,b,w;
cin >> a >> b >> w;
//建立无向图
g[a].push_back(make_pair(b,w));
g[b].push_back(make_pair(a,w));
}
vector<vector<int>> dist1(n+1,vector<int>(2,INF));
vector<vector<int>> dist2(n+1,vector<int>(2,INF));
dijkstra(g, dist1, hs, 1);
dijkstra(g, dist2, hs, n);
//lambda:引用铺货
auto get = [&] (int a)
{
return max(min(dist1[a][0],dist1[a][1]),min(dist2[a][0],dist2[a][1]));
};
//枚举相遇点
int ans = INF;
for(int i = 1; i <= n; i++){
ans = min(ans,get(i));
}
if(ans == INF) cout << "-1" << endl;
else cout << ans << endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> T;
while(T--){
solve();
}
return 0;
}