牛客周赛37 A - F
题目 | 知识点 |
---|---|
A | 签到 |
B | 暴力 |
C | 暴力 + 数学 |
D | 博弈论 |
E | BFS |
F | DFS + 剪枝优化 or DP(背包) |
A 雾之湖的冰精
【签到题】
#include<bits/stdc++.h>
using namespace std;
#define pii pair<int, int>
#define pdd pair<double, double>
#define pll pair<ll, ll>
#define endl '\n'
typedef long long ll;
inline void solve()
{
int a, b;
cin >> a >> b;
if(a+b <= 9) cout << "Yes" << endl;
else cout << "No" << endl;
}
int main()
{
cout << fixed << setprecision(10);
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
solve();
return 0;
}
B 博丽神社的巫女
【签到】【暴力】
给a数组排个序,从前往后找到第一个大于x的位置即可。
#include<bits/stdc++.h>
using namespace std;
#define pii pair<int, int>
#define pdd pair<double, double>
#define pll pair<ll, ll>
#define endl '\n'
typedef long long ll;
inline void solve()
{
int n, x;
cin >> n >> x;
vector<int> a(n+1);
for(int i=1; i<=n; i++)
cin >> a[i];
sort(a.begin()+1, a.end());
for(int i=1; i<=n; i++) {
if(a[i] > x) {
cout << i-1 << " " << x - a[i-1] << endl;
return;
}
}
cout << n << " " << x-a[n] << endl;
}
int main()
{
cout << fixed << setprecision(10);
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
solve();
return 0;
}
C 红魔馆的馆主
【暴力】+【数学】
赛后数据加强了,update一下正解
——2024.3.22
同样是枚举,不过稍加推导,可以避免超出long long的范围。
并且处理了添加的数字串包含前导零的情况(例如:05其实会比115更优)
#include<bits/stdc++.h>
using namespace std;
#define pii pair<int, int>
#define pdd pair<double, double>
#define pll pair<ll, ll>
#define endl '\n'
typedef long long ll;
inline void solve()
{
ll n;
cin >> n;
if(n % 495 == 0) {
cout << -1 << endl;
return;
}
n = n % 495;
for(int i=0; i<=9; i++) {
if((n*10 + i) % 495 == 0) {
cout << i << endl;
return;
}
}
for(int i=0; i<=99; i++) {
if((n*100 + i) % 495 == 0) {
if(i < 10) cout << 0;
cout << i << endl;
return;
}
}
for(int i=0; i<=495; i++) {
if((n*1000 + i) % 495 == 0) {
if(i < 100) cout << 0;
if(i < 10) cout << 0;
cout << i << endl;
return;
}
}
}
int main()
{
cout << fixed << setprecision(10);
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
solve();
return 0;
}
赛时AC的原题解
【暴力】
这题的数据比较善良,暴力就可以过。
其实按理说,这道题严格按照1e18
的范围的话,暴力写是会爆long long,但数据应该是没有极端的1e18这样的数据。
暴力的做法就是从1位数开始枚举枚举后面添加数字,其实比较保守的是枚举到后4位,但枚举到3位数就过了。
可能做法有点假,但被我水过了。
#include<bits/stdc++.h>
using namespace std;
#define pii pair<int, int>
#define pdd pair<double, double>
#define pll pair<ll, ll>
#define endl '\n'
typedef long long ll;
inline void solve()
{
ll n;
cin >> n;
if(n % 495 == 0) {
cout << -1 << endl;
return;
}
for(int i=0; i<=9; i++) {
if((n*10+i) % 495 == 0) {
cout << i << endl;
return;
}
}
for(int i=0; i<=9; i++) {
for(int j=0; j<=9; j++) {
if(((n*10+i)*10+j) % 495 == 0) {
cout << i*10+j << endl;
return;
}
}
}
for(int i=100; i<=999; i++) {
if((n*1000 + i) % 495 == 0) {
cout << i << endl;
return;
}
}
}
int main()
{
cout << fixed << setprecision(10);
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
solve();
return 0;
}
D 迷途之家的大贤者
【博弈论】
小紫的目标是让字典序更小,那么最后剩下的字符串一定是只有单个字符。
而为了不让小红有操作的余地,小紫的最优策略就是在第一次操作就删得只剩一个字符。
那么,与其等着小紫来删,作为先手的小红不如第一轮就删的只剩一个而留下更大的字符。
由于删除的子串必须是连续的,一次性删除之后留下的只能是第一个元素或最后一个元素。
所以输出
m
a
x
(
s
[
n
−
1
]
,
s
[
0
]
)
max(s[n-1], s[0])
max(s[n−1],s[0]) 即可。
#include<bits/stdc++.h>
using namespace std;
#define pii pair<int, int>
#define pdd pair<double, double>
#define pll pair<ll, ll>
#define endl '\n'
typedef long long ll;
inline void solve()
{
int n;
string s;
cin >> n >> s;
cout << max(s[n-1], s[0]) << endl;
}
int main()
{
cout << fixed << setprecision(10);
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
solve();
return 0;
}
E 魔法之森的蘑菇
【BFS】
常规的地图上跑BFS,不过这题加了点创新,如果没有遇到蘑菇只能按一个方向走。这点其实挺好办的,在BFS队列中加一个维度:通往下一个点的方向。
由于这道题方向也是一个维度,走到同一个点时,下一个方向不同,算作不同情况
。因此,bfs记录已走过的点,也必须记录三个维度。
#include<bits/stdc++.h>
using namespace std;
#define pii pair<int, int>
#define pdd pair<double, double>
#define pll pair<ll, ll>
#define endl '\n'
typedef long long ll;
inline void solve()
{
int n, m;
cin >> n >> m;
vector<vector<char>> mp(n+1, vector<char>(m+1));
int sx, sy;
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++) {
cin >> mp[i][j];
if(mp[i][j] == 'S') {
sx = i;
sy = j;
}
}
vector<int> dx = {1, 0, 0, -1};
vector<int> dy = {0, 1, -1, 0};
queue<array<int, 4>> q;
set<array<int, 3>> vis; // 记录已经走过的点
// 四个方向都入队
for(int i=0; i<4; i++) {
q.push({sx, sy, 0, i});
vis.insert({sx, sy, i});
}
while(!q.empty()) {
// x y坐标 tot步数 d方向
auto [x, y, tot, d] = q.front();
q.pop();
if(mp[x][y] == 'T') {
cout << tot << endl;
return;
}
if(mp[x][y] == '.' || mp[x][y] == 'S') {
int xx = x + dx[d];
int yy = y + dy[d];
if(xx>=1 && xx<=n && yy>=1 && yy<=m) {
if(!vis.count({xx, yy, d})) {
q.push({xx, yy, tot+1, d});
vis.insert({xx, yy, d});
}
}
}
if(mp[x][y] == '*') {
for(int i=0; i<4; i++) {
if(i+d != 3) {
int xx = x + dx[i];
int yy = y + dy[i];
if(xx>=1 && xx<=n && yy>=1 && yy<=m) {
if(!vis.count({xx, yy, i})) {
q.push({xx, yy, tot+1, i});
vis.insert({xx, yy, i});
}
}
}
}
}
}
cout << -1 << endl;
}
int main()
{
cout << fixed << setprecision(10);
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t;
cin >> t;
while(t --) {
solve();
}
return 0;
}
F 三途川的摆渡人
【DFS】【剪枝优化】
重复的数肯定是最好去掉,那么用set来存数就好。
又由于
a
≤
200
a≤200
a≤200 所以实际上的数并不多,跑个加剪枝的DFS暴力枚举留下的数即可。
#include<bits/stdc++.h>
using namespace std;
#define pii pair<int, int>
#define pdd pair<double, double>
#define pll pair<ll, ll>
#define endl '\n'
typedef long long ll;
inline void solve()
{
int n;
cin >> n;
vector<int> a(n+1);
int s = -1;
set<int> st;
for(int i=1; i<=n; i++) {
cin >> a[i];
if(i == 1) s = a[i];
else s &= a[i];
st.insert(a[i]);
}
if(s) {
cout << -1 << endl;
return;
}
vector<int> b;
for(int x: st) {
b.push_back(x);
}
int m = b.size();
int res = m;
map<int, bool> mp;
function<void(int, int)> dfs = [&](int s, int tot) {
if(tot >= res) return;
if(s == 0) {
res = min(res, tot);
return;
}
for(int i=0; i<m; i++) {
if(mp[b[i]]) continue;
mp[b[i]] = 1;
dfs(s&b[i], tot+1);
mp[b[i]] = 0;
}
};
for(int i=0; i<m; i++) {
mp[b[i]] = 1;
dfs(b[i], 1);
mp[b[i]] = 0;
}
cout << n - res << endl;
}
int main()
{
cout << fixed << setprecision(10);
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t;
cin >> t;
while(t --) {
solve();
}
return 0;
}
【DP】【背包】
#include<bits/stdc++.h>
using namespace std;
#define pii pair<int, int>
#define pdd pair<double, double>
#define pll pair<ll, ll>
#define endl '\n'
typedef long long ll;
inline void solve()
{
int n;
cin >> n;
vector<int> a(n+1);
int s = -1;
set<int> st;
for(int i=1; i<=n; i++) {
cin >> a[i];
if(i == 1) s = a[i];
else s &= a[i];
st.insert(a[i]);
}
if(s) {
cout << -1 << endl;
return;
}
vector<int> b;
b.push_back(0);
for(int x: st) {
b.push_back(x);
}
int m = b.size()-1;
vector<vector<int>> dp(m+5, vector<int>(300, 1e9));
for(int i=1; i<=m; i++) {
dp[i][b[i]] = 1;
for(int j=0; j<256; j++)
dp[i][j] = min(dp[i][j], dp[i-1][j]);
for(int j=0; j<256; j++)
dp[i][j&b[i]] = min(dp[i][j&b[i]], dp[i-1][j] + 1);
}
if(dp[m][0] == 1e9) cout << -1 << endl;
else cout << n - dp[m][0] << endl;
}
int main()
{
cout << fixed << setprecision(10);
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t;
cin >> t;
while(t --) {
solve();
}
return 0;
}