Codeforces Round 1065 (Div. 3)题解
A. Shizuku Hoshikawa and Farm Legs
签到题,第一眼看到的时候以为要解鸡兔同笼,但是直接观察就能得出答案了
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ll long long
#define vi vector<int>
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define endl '\n'
const int INF=1e18,N=2e5,MOD=1e9+7;void solve(){int n;cin>>n;if(n&1) cout<<0<<endl;else{n/=2;n/=2;cout<<n+1<<endl;}
}signed main(){ios::sync_with_stdio(false);cin.tie(0);int T=1;cin>>T;while(T--)solve();return 0;
}
[B - Yuu Koito and Minimum Absolute Sum]
所谓的差值求和max化简下来就是求max(|an-a1|),所以我们直接特判即可,尽量使得字典序最小
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ll long long
#define vi vector<int>
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define endl '\n'
const int INF=1e18,N=2e5,MOD=1e9+7;void solve(){int n;cin>>n;vi a(n);for(int i=0;i<n;i++){cin>>a[i];}if(a[0]==-1&&a[n-1]==-1) a[0]=a[n-1]=0;if(a[0]==-1) a[0]=a[n-1];else if(a[n-1]==-1) a[n-1]=a[0];if(a[0]>a[n-1]) cout<<a[0]-a[n-1]<<endl;else cout<<a[n-1]-a[0]<<endl;for(int i=0;i<n;i++){if(a[i]==-1) a[i]=0;cout<<a[i]<<' ';}cout<<endl;
}signed main(){ios::sync_with_stdio(false);cin.tie(0);int T=1;cin>>T;while(T--)solve();return 0;
}
C2 - Renako Amaori and XOR Game (hard version)
这个题目直接看的Hard Version,因为位运算多半是找规律的题目,赌一下
如果最终A和M的得分相同,那么这两个得分异或起来就是0,等价于a、b所有元素异或和为0,那么这样就好特判了。
不然的话,我们找到他们异或起来第一位为1的值(第一位不一样的),就是所有元素异或和第一位不一样的,找到之后做标记,看这个位是在哪里出现(且ai、bi的这个位不能同时为1,否则没有意义),如果位置是在奇数上就A赢,否则M赢
D/F - Rae Taylor and Trees
这个题目不能用DFS写,因为边太多了,存N阶完全图会MLE,所以我们优化一下DFS的来由,就是出现了多个连通分量,既然u和v要满足小的一定排在前面,所以就不能出现这种情况,小的元素在后面于是连不了前面的连通分量,而前面的连通分量都是有前面的最小元素主导的,后面的小元素连不过来的原因是这个元素比前面的最小元素还要小,为了保证两者所在连通分量不同,只需要保证他们没有连相同的大元素即可, 问题转换为前面的最小元素连不了后面的大元素,连不了是因为min前>max后,所以存一个后缀max数组再遍历一遍即可
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ll long long
#define vi vector<int>
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define endl '\n'
const int INF=1e18,N=2e5,MOD=1e9+7;void solve(){int n;cin>>n;vi p(n+5);for(int i=1;i<=n;i++){cin>>p[i];}vi suf(n+5);int pmn=INF;for(int i=n;i>=1;i--){suf[i]=max(p[i],suf[i+1]);}for(int i=1;i<n;i++){pmn=min(p[i],pmn);if(pmn>suf[i+1]) {cout<<"No\n";return;}}cout<<"Yes\n";
}signed main(){ios::sync_with_stdio(false);cin.tie(0);int T=1;cin>>T;while(T--)solve();return 0;
}
这样子也隐含表示了建树的过程,如果可以建树的话,前面的连通分量由最小数主导,后面的连通分量可以连过来是因为两个连通分量共同连接了最大的元素,所以我们把依次出现的前缀最小值维护起来即可接着分为最小值不变型连接和最小值更新时连接两种情况处理即可
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ll long long
#define vi vector<int>
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define endl '\n'
const int INF=1e18,N=2e5,MOD=1e9+7;void solve(){int n;cin>>n;vi p(n+5);for(int i=1;i<=n;i++){cin>>p[i];}vector<pair<int,int>> suf(n+5);suf[n]={p[n],n};int pmn=INF;for(int i=n-1;i>=1;i--){if(p[i]>suf[i+1].fi){suf[i]={p[i],i};}else suf[i]=suf[i+1];}vi mn;for(int i=1;i<=n;i++){if(p[i]<pmn){pmn=p[i];mn.pb(i);}}for(int i=0;i<mn.size()-1;i++){int cur=mn[i],nxt=mn[i+1];if(p[cur]>suf[nxt].fi) {cout<<"No\n";return ;}}cout<<"YES\n";int cur=mn[0],nxt=1;for(int i=2;i<=n;i++){if(nxt<mn.size()&&i==mn[nxt]){cur=mn[nxt];nxt++;}else cout<<p[cur]<<' '<<p[i]<<endl;}for(int i=0;i<mn.size()-1;i++){int u=p[mn[i]],v=suf[mn[i+1]].fi;cout<<u<<' '<<v<<endl;}
}signed main(){ios::sync_with_stdio(false);cin.tie(0);int T=1;cin>>T;while(T--)solve();return 0;
}
很棒的一场Div3!