牛客练习赛61
比赛地址:
前言:这场比赛感觉自己脑袋不太清醒,导致了罚时爆表A题把continue写成了retrurn居然一直都没发现,C也不明原因WA了好多次,好在最后一下连过三题苟了个四题尾总算没有掉分。(我真是个憨憨)
A. 打怪
基本思路:
- 由于勇士是先手,所以勇士的攻击如果大于怪物的血量,一定能无限秒杀怪物输出-1;
- 否则我们看下在打一只怪的时候勇士会被攻击到几次,就能算出打一只怪勇士血量的损失(注意先后手);
- 然后用勇士的血量去除打一只怪的血量损失理论上就是答案了,但是注意如果刚好整除的话,由于勇士每次是给与怪物最后一击的,所以如果整除说明最后一次怪物先把勇士打死了,所以这个时候减个一;
参考代码:
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
#define IO std::ios::sync_with_stdio(false)
#define ll long long
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define per(i, l, r) for (int i = l; i >= r; i--)
#define mset(s, _) memset(s, _, sizeof(s))
#define pb push_back
#define pii pair <int, int>
#define pdd pair <double, double>
#define mp(a, b) make_pair(a, b)
#define INF 1e18
inline int read() {
int x = 0, neg = 1; char op = getchar();
while (!isdigit(op)) { if (op == '-') neg = -1; op = getchar(); }
while (isdigit(op)) { x = 10 * x + op - '0'; op = getchar(); }
return neg * x;
}
inline void print(int x) {
if (x < 0) { putchar('-'); x = -x; }
if (x >= 10) print(x / 10);
putchar(x % 10 + '0');
}
int a,b,c,d;
signed main() {
IO;
int t;
cin >> t;
while (t-- > 0) {
cin >> a >> b >> c >> d;
if (b >= c) { // 能秒杀怪,无损失;
cout << -1 << '\n';
continue;
}
int k1 = c % b == 0 ? c / b - 1 : c / b;//整除的话,由于先手要减一;
int z = d * k1;//杀一只怪勇士血量的损失;
if (a % z == 0) cout << a / z - 1;//整除要减一;
else cout << a / z;
cout << '\n';
}
return 0;
}B. 吃水果
基本思路:
这题应该很简单贪心的策略,我们要想办法将苹果和香蕉的数量凑到相同再一起吃完,所以我们将苹果和香蕉里较小的那个先最快的加到一样多,然后再一天天吃就是了。
参考代码:
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
#define IO std::ios::sync_with_stdio(false)
#define int long long
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define per(i, l, r) for (int i = l; i >= r; i--)
#define mset(s, _) memset(s, _, sizeof(s))
#define pb push_back
#define pii pair <int, int>
#define pdd pair <double, double>
#define mp(a, b) make_pair(a, b)
#define INF 1e18
inline int read() {
int x = 0, neg = 1; char op = getchar();
while (!isdigit(op)) { if (op == '-') neg = -1; op = getchar(); }
while (isdigit(op)) { x = 10 * x + op - '0'; op = getchar(); }
return neg * x;
}
inline void print(int x) {
if (x < 0) { putchar('-'); x = -x; }
if (x >= 10) print(x / 10);
putchar(x % 10 + '0');
}
int n,m;
signed main() {
IO;
int t;
cin >> t;
while (t-- > 0) {
cin >> n >> m;
int cnt = 0;
if(n > m) swap(n,m); // 令n是小的那个;
int ans = m;
while (n < m) { //加到两者数目一样多;
n += n;
cnt++;
}
ans += cnt;
cout << ans << endl;
}
return 0;
}C. 四个选项
基本思路:
因为只有12道题,而且限制条件很多,明显的dfs+剪枝就能过,基本上就是一个裸的dfs再根据每种选项的数量和那m个额外条件剪枝就是了,就是出了一个莫名其妙的问题让我WA了好久,具体实现可以参考代码。
参考代码:
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
#define IO std::ios::sync_with_stdio(false)
#define ll long long
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define per(i, l, r) for (int i = l; i >= r; i--)
#define mset(s, _) memset(s, _, sizeof(s))
#define pb push_back
#define pii pair <int, int>
#define pdd pair <double, double>
#define mp(a, b) make_pair(a, b)
#define INF 1e18
inline int read() {
int x = 0, neg = 1; char op = getchar();
while (!isdigit(op)) { if (op == '-') neg = -1; op = getchar(); }
while (isdigit(op)) { x = 10 * x + op - '0'; op = getchar(); }
return neg * x;
}
inline void print(int x) {
if (x < 0) { putchar('-'); x = -x; }
if (x >= 10) print(x / 10);
putchar(x % 10 + '0');
}
int na,nb,nc,nd,m;
int ans = 0;
map<int,vector<int>> memo;
void dfs(int s,string str,int a,int b,int c,int d) {
if (a > na || b > nb || c > nc || d > nd) return; // 数量超过了就return;
if (s == 12) {
if (a == na && b == nb && c == nc && d == nd) ans++;
return;
}
for (int i = 0; i < 4; i++) {
char ct = (char) ('A' + i);
bool v = true;
if (memo.count(s)) { // 要满足和这些都相同;
for (auto it : memo[s]) {
if (it < s && ct != str[it]) {
v = false;
break;
}
}
}
if (!v) continue;
dfs(s + 1, str + ct, i == 0 ? a + 1 : a, i == 1 ? b + 1 : b, i == 2 ? c + 1 : c, i == 3 ? d + 1 : d);
}
}
signed main() {
IO;
cin >> na >> nb >> nc >> nd >> m;
memo.clear();
ans = 0;
rep(i, 1, m) {
int x, y;
cin >> x >> y;
x--, y--;
if (y > x) swap(x, y);
memo[x].push_back(y);
memo[y].push_back(x);//不加这个就WA了,虽然我感觉只往前找没问题...;
}
dfs(0, "", 0, 0, 0, 0);
cout << ans << '\n';
return 0;
}D. 最短路变短了
基本思路:
- 这题其实比较套路这种将边反向啊,或者两个点再多连一条边和原先最短路比的,都差不多是这么做;
- 我们先跑一遍dijkstra算出起点到所有节点的最短路,记录在数组dis1中,然后再反向建边算出终点到所有节点的最短路记录在数组dis2中;
- 我们将边反向后经过这条反向边(原)(u,v)的最短路就应该为 = dis1[v] + dis2[u] + w,将这条经过反向边的最短路和原先的最短路比,就能知道新最短路是否变短了;
参考代码:
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
#define IO std::ios::sync_with_stdio(false)
#define int long long
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define per(i, l, r) for (int i = l; i >= r; i--)
#define mset(s, _) memset(s, _, sizeof(s))
#define pb push_back
#define pii pair <int, int>
#define pdd pair <double, double>
#define mp(a, b) make_pair(a, b)
#define INF 1e18
inline int read() {
int x = 0, neg = 1; char op = getchar();
while (!isdigit(op)) { if (op == '-') neg = -1; op = getchar(); }
while (isdigit(op)) { x = 10 * x + op - '0'; op = getchar(); }
return neg * x;
}
inline void print(int x) {
if (x < 0) { putchar('-'); x = -x; }
if (x >= 10) print(x / 10);
putchar(x % 10 + '0');
}
const int maxn = 1e5 + 10;
const int maxm = 2e5 + 10;
struct Edge{
int to,next,val;
}edge1[maxm],edge2[maxm];
int n,m;
int head1[maxn],head2[maxn];
int cnt1 = 0, cnt2 = 0;
void add_edge1(int u,int v,int w) {
edge1[++cnt1] = {v, head1[u], w};
head1[u] = cnt1;
}
void add_edge2(int u,int v,int w) {
edge2[++cnt2] = {u, head2[v], w};//反向加的边;
head2[v] = cnt2;
}
int dis1[maxn],dis2[maxn];
bool vis[maxn];
void dijkstra1(int k) {//正向dijkstra;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> q;
while (!q.empty()) q.pop();
for (int i = 1; i <= n; i++) dis1[i] = INF;
mset(vis,false);
dis1[k] = 0;
q.push(make_pair(0, k));
while (!q.empty()) {
int s = q.top().second;
q.pop();
if (vis[s]) continue;
vis[s] = true;
for (int i = head1[s]; i != -1; i = edge1[i].next) {
if (dis1[edge1[i].to] > dis1[s] + edge1[i].val) {
dis1[edge1[i].to] = dis1[s] + edge1[i].val;
q.push(make_pair(dis1[edge1[i].to], edge1[i].to));
}
}
}
}
void dijkstra2(int k) {//反向dijkstra;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> q;
while (!q.empty()) q.pop();
for (int i = 1; i <= n; i++) dis2[i] = INF;
mset(vis, false);
dis2[k] = 0;
q.push(make_pair(0, k));
while (!q.empty()) {
int s = q.top().second;
q.pop();
if (vis[s]) continue;
vis[s] = true;
for (int i = head2[s]; i != -1; i = edge2[i].next) {
if (dis2[edge2[i].to] > dis2[s] + edge2[i].val) {
dis2[edge2[i].to] = dis2[s] + edge2[i].val;
q.push(make_pair(dis2[edge2[i].to], edge2[i].to));
}
}
}
}
vector<int> memo[maxm];//记录一下边;
signed main() {
IO;
n = read(),m = read();
cnt1 = 0, cnt2 = 0;
mset(head1, -1);
mset(head2, -1);
rep(i, 1, m) {
int u, v, w;
u = read(),v = read(),w = read();
memo[i] = {u, v, w};
add_edge1(u, v, w);
add_edge2(u, v, w);
}
dijkstra1(1);
dijkstra2(n);
int temp = dis1[n];
int q;
q = read();
while (q-- > 0) {
int x;
x = read();
int u = memo[x][0], v = memo[x][1], w = memo[x][2];
if (dis1[v] + dis2[u] + w < temp) { // 记得v,和u要相反;
cout << "YES" << '\n';
} else cout << "NO" << '\n';
}
return 0;
}

京公网安备 11010502036488号