A
A题你可以用把n,m转成二进制后,按题目模拟,但是,有更快捷的做法。
将n,m转为二进制后,你会发现,每个位有1为1,无一为0,这和逻辑或运算方法一模一样,
所以只要将n,m进行或运算就可以了。
#include<bits/stdc++.h>
using namespace std;
string s;
void init(){
}
signed main(){
int n,m,k;
cin >> n >> m;
cout << (n | m) << endl;
return 0;
}
B
这里我们分类讨论一下。
n表示x,z中最小的,m表示最最大的。
如果((n < y && y < 0)|| (m > y && y > 0))即,x,z都被y 与原点隔开了,输出-1
如果x,y不同号,直接输出x的绝对值,因为Takahashi可以直接走过去。
如果(y < x && x < 0) || (y > x && x > 0) ,即x的绝对值小于y的绝对值,Takahashi也可以直接走过去 。
剩余情况Takahashi就先拿锤子,再走到x就可以了。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
#define _clear(q) while (!q.empty()){q.pop();}
int yes(int dx){cout << "Yes" << endl;return 0;}
int no(int dx){cout << "No" << endl;return 0;}
string s;
void init(){
}
bool th(int a,int b){
return ((a < 0 && b < 0) || (a > 0 && b > 0));
}
signed main(){
int n,m,k;
init();
int x,y,z;
cin >> x >> y >> z;
n = max(x,z);
m = min(x,z);
if (n < y && y < 0) cout << -1 << endl;
else if (m > y && y > 0) cout << -1 << endl;
else{
if (!th(x,y)) cout << abs(x) << endl;
else{
if ((y < x && x < 0) || (y > x && x > 0)) cout << abs(x) << endl;
else{
int step = 0;
int now = z;
step += abs(z);
step += abs(x - z);
cout << step << endl;
}
}
}
return 0;
}
C
这题是个经典的DFS,我们首先建一棵树,每棵树的边都是双向的,这里,我们利用DFS的可回溯来求答案。
我们需要一个 函数 DFS(x,fa)。
x 表示当前节点的编号,fa表示他的父亲。
DFS(x,fa)的返回值表示本路径是否可以从x到y。
其他东西见代码
写法一:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
#define _clear(q) while (!q.empty()){q.pop();}
int yes(int dx){cout << "Yes" << endl;return 0;}
int no(int dx){cout << "No" << endl;return 0;}
void init(){
}
vector <int> G[N];
int n,s,t;
vector <int> ans;
bool DFS(int x,int fa){
if (x == t){
ans.push_back(x);
// 如果当前节点就是我们要找的终点,说明这条路可行。
return true;
}
for (int i = 0 ; i < G[x].size() ; i ++){
int v = G[x][i];
if (v != fa && DFS(v,x)) {
// 递归的可回溯性,如果这个点的子孙是终点,那说明路径上一定有它。
ans.push_back(x);
return true;
}
}
return false;
}
signed main(){
init();
cin >> n >> s >> t;
for(int i = 1 ; i < n ; i ++) {
int u,v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
DFS(s , -1);
// 因为我们是从终点开始放入答案,所以要倒着输出结果,方法二则是优化了这个步骤。
for (int i = ans.size() - 1 ; i >= 0 ; i --) cout << ans[i] << " ";
return 0;
}
写法二:
因为上述做法是倒叙的,所以,我们为了优化一个vector的复杂度,从终点开始,搜起点。
搜到了就将它输出。省掉了倒着输出的这个步骤。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define MAXN 1048586
#define M 5005
#define N 500005
#define int long long
#define endl "\n"
#define _clear(q) while (!q.empty()){q.pop();}
int yes(int dx){cout << "Yes" << endl;return 0;}
int no(int dx){cout << "No" << endl;return 0;}
void init(){
}
vector <int> G[N];
int n,s,t;
bool DFS(int x,int fa){
if (x == t){
cout << x << " ";
return true;
}
for (int i = 0 ; i < G[x].size() ; i ++){
int v = G[x][i];
if (v != fa && DFS(v,x)) {
cout << x << " ";
return true;
}
}
return false;
}
signed main(){
init();
cin >> n >> s >> t;
for(int i = 1 ; i < n ; i ++) {
int u,v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
swap(s,t);
// swap(s,t)将s,t反了一下,s变成了终点,t变成了起点
DFS(s,-1);
return 0;
}
E
这题有多种做法,但是巨菜的本人只提供二分答案。
这里,我们把每个篮子想象成n根柱子,每个柱子高a[i],我们二分刀的高度,
把每个柱子从下到上切掉这段距离,如果小于这段就能取多少取多少,(问题的转化)
如果总和大于k就记录一下答案,然后不断减少,直至不能再减。
这样肯定会多砍。所以我们要求出多砍了多少根,把他们加回去,具体细节见代码。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define MAXN 1048586
#define M 5005
#define N 500005
string s;
int a[N];
void init(){
}
int n,m,k;
bool check(int x){
int cnt = 0 ;
for(int i = 1 ; i <= n ;i ++) cnt += min(x,a[i]);
return cnt >= k;
}
signed main(){
init();
cin >> n >> k;
int l = 0 , r = -1e18;
for (int i = 1 ; i <= n ;i ++) cin >> a[i], r = max(r , a[i]);
int ans = 0;
while (l <= r){
int mid = l + r >> 1;
if (check(mid)) {
ans = mid;
r = mid - 1;
}
else l = mid + 1;
}
// 二分答案,ans是二分的结果。
int sum = 0;
for (int i = 1 ; i <= n ; i ++) {
sum += min(a[i] , ans);
}
int t = sum - k;
for (int i = n ; i >= 1 && t > 0 ; i --){
if (a[i] <= ans) continue;
// 思考一下,你会发现如果a[i] <= ans,那么ans对答案都没有多贡献1,所以a[i] <= ans时,不用加。
a[i] ++;
t --;
}
for (int i = 1 ; i <= n ; i ++){
a[i] -= min(a[i] , ans);
// 算出结果。
cout << a[i] << " ";
}
return 0;
}