比赛链接:Dashboard - Codeforces Round #835 (Div. 4) - Codeforces
A: 排序
题意:给定三个数,求第二大数
思路:排一遍序,输出第二个数即可
代码:
#include<bits/stdc++.h>
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N=2e5+10;
int a[N];
inline void solve(){
for(int i=1;i<=3;i++) cin>>a[i];
sort(a+1,a+1+3);
cout<<a[2]<<"\n";
}
signed main(){
fast;
int T;cin>>T;
while(T--) solve();
}
B: 排序
题意:找最大字符
思路:排序即可
代码:
#include<bits/stdc++.h>
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N=2e5+10;
int a[N];
inline void solve(){
int n;string s;cin>>n>>s;
sort(s.begin(),s.end());
char aa=s[s.size()-1];
int ans=aa-'a'+1;
cout<<ans<<"\n";
}
signed main(){
fast;
int T;cin>>T;
while(T--) solve();
}
C:贪心
题意:给定长度为N的数组,找每个数与最大数的差值,如果本身就是最大数,则差值为最大数-次大数
思路:排一次序。依次运算即可
代码:
#include<bits/stdc++.h>
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N=2e5+10;
int a[N],b[N];
inline void solve(){
int n;cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],b[i]=a[i];
sort(b+1,b+1+n);
if(b[1]==b[n]){
for(int i=1;i<=n;i++) cout<<"0 ";
cout<<"\n";return;
}
for(int i=1;i<=n;i++){
if(a[i]==b[n]) cout<<(a[i]-b[n-1])<<" ";
else cout<<(a[i]-b[n])<<" ";
}
cout<<"\n";
}
signed main(){
fast;
int T;cin>>T;
while(T--) solve();
}
D:思维+模拟
这里直接说结论吧
结论:找到山谷后,后面的上升序列只能一直升,不能降
代码:
#include<bits/stdc++.h>
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N=2e5+10;
int a[N],d[N];
inline void solve(){
int n;cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
bool ok=false;//表示是否为升序
for(int i=2;i<=n;i++){
if(a[i]==a[i-1]) continue;
if(ok){
if(a[i]<a[i-1]){
cout<<"NO\n";return;
}
}
if(a[i]>a[i-1]) ok=true;
}
cout<<"YES\n";
}
signed main(){
fast;
int T;cin>>T;
while(T--) solve();
}
E:前后缀
题意:给定 01 串,求最多反转其中一个位置的前提下,最大的逆序对数
吐槽:一开始考虑贪心,直接搞TLE了。然后又O(N^2)求逆序对,也炸了。没有脑子捏。。。
思路:这里用前后缀进行优化
先算出初始的逆序对数量,接下来考虑每个点翻转对答案的影响。
如果是 0 变成 1 ,那么对答案的影响是减去后面的 1 的数量,加上前面 0 的数量。
如果是 1 变成 0 ,那么对答案的影响是减去后面 0 的数量,加上前面 1 的数量。
用前后缀分别维护出一个位置前面和后面 1 和 0 的数量即可。
代码:
#include<bits/stdc++.h>
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N=2e5+10;
int arr[N],p1[N],s1[N],p0[N],s0[N];
//p1:表示当前位置前面有多少个1
//p0:表示当前位置前面有多少个0
//s1:表示当前位置后面有多少个1
//s0:表示当前位置后面有多少个0
inline void solve(){
int n;cin>>n;int sum=0;//sum记录逆序对数
for(int i=1;i<=n;i++) cin>>arr[i];
int a=0,b=0;//a表示1的个数,b表示0的个数
for(int i=n;i>=1;i--){
if(arr[i]==1){
s1[i]=a;s0[i]=b;
a++;sum+=b;
}
else{
s1[i]=a;s0[i]=b;b++;
}
}
a=0,b=0;
for(int i=1;i<=n;i++){
if(arr[i]==1){
p1[i]=a;p0[i]=b;a++;
}
else{
p1[i]=a;p0[i]=b;b++;
}
}
int ans=sum;
for(int i=1;i<=n;i++){//进行枚举判断
if(arr[i]) ans=max(ans,sum+p1[i]-s0[i]);
else ans=max(ans,sum-p1[i]+s0[i]);
}
//ps:p0和s1数组没有用到捏...q.q
cout<<ans<<"\n";
}
signed main(){
int T;cin>>T;
while(T--) solve();
}
F:二分+贪心
题意:有 n 个任务,每个任务做完会获得 ai 的奖励,任务做完会有 x 天的 cd ,必须在 x+1 天才能继续完成这个任务。给定参数 c,d ,请问在 d 天获得至少 c 的奖励的最大cd是多少。
思路:先考虑特判,先从大到小sort一遍。
如果不存在冷却时间的情况下,如果每天都选择最大的得分(maxx),d*maxx<c,则无解。
再考虑无穷解的情况:同样如果不存在冷却时间的情况下,每天都选择一个数,sum记录和,如果sum>=c,则是无穷解。为什么?
因为,如果前面有一个大于c的,就可以是无穷解,或者是2个的和>c,或者是d个的和>c
然后就是考虑一半情况:这里选择二分答案
#include<bits/stdc++.h>
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N=2e5+10;
int a[N],n,c,d;
bool check(int mid){
int sum=0;
for(int i=1;i<=min(mid+1,n);i++){
for(int j=i;j<=d;j+=mid+1){
sum+=a[i];
if(sum>=c) return true;
}
}
return false;
}
inline void solve(){
cin>>n>>c>>d;
int maxx=0,sum=0;
for(int i=1;i<=n;i++){
cin>>a[i];maxx=max(maxx,a[i]);
}
sort(a+1,a+1+n,greater<int>());
for(int i=1;i<=min(d,n);i++) sum+=a[i];
if(d*maxx<c) cout<<"Impossible\n";
else{
if(sum>=c){
cout<<"Infinity\n";return;
}
int L=0,R=2e5;
while(L+1<R){
int mid=L+R>>1;
if(check(mid)) L=mid;
else R=mid;
}
cout<<L<<"\n";
}
}
signed main(){
int T;cin>>T;
while(T--) solve();
}
G:DFS
题意: 给定一棵带边权的树,给定起点 a 和终点 b ,从 a 出发,刚开始的分数为 0 ,每走过一条边会使分数异或上这个值,要求最后走到 b 的分数为 0 ,并可以进行任意一次传送,求能否满足要求
思路:转化一下观点。从a到b,使得最终到达b时,xor为0。双向DFS一下。从a跑一遍,从b跑一遍。比如从a跑到点x的值为m,从b跑到点y的值为n,那么我们一定可以知道m==n
为什么?
因为题目中说了,可以传送一次点位,那么x点就可以直接传到y点,这样路径就连接起来了。
如果有交点怎么办?
其实交点就可以直接忽略掉,因为是xor,所以两条路径都有这个点,那么就xor为0了,可以直接消除。
所以最终做法:我们先搜一遍a,把xor值放入set中,再搜一遍b,判断xor值是否在set中出现即可
代码:
#include<bits/stdc++.h>
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N=2e5+10;
typedef pair<int,int>PII;
int n,a,b;
vector<PII>ve[N];
set<int>se;
bool ok;
void dfs1(int u, int fa, int sum){
se.insert(sum);
for(auto [x, y] : ve[u]){
if(x == fa) continue;
if(x != b)
dfs1(x, u, sum ^ y);
}
}
void dfs2(int u, int fa, int sum){
for(auto [x, y] : ve[u]){
if(x == fa) continue;
if(se.count(sum ^ y)) ok = 1;
dfs2(x, u, sum ^ y);
}
}
void solve(){
cin >> n >> a >> b;
ok = false;se.clear();
for(int i = 1; i <= n; i ++ ) ve[i].clear();
for(int i = 1; i <= n - 1; i ++ ){
int x, y, z;cin >> x >> y >> z;
ve[x].push_back({y, z});
ve[y].push_back({x, z});
}
dfs1(a, 0, 0);dfs2(b, 0, 0);
if(ok) cout << "YES\n";
else cout << "NO\n";
}
signed main(){
int T;cin>>T;
while(T--) solve();
}