Codeforces Round 1023 (Div. 2) A - F1
A. LRC and VIP
把最大值分一组,其他值分一组即可。
如果整个数组一样,那就是NO。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
//using i128 = __int128_t;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n;
cin>>n;
int mx=0;
int idx=0;
vector<int> a(n+10);
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]>mx){
mx=a[i];
idx=i;
}
}
for(int i=1;i<=n;i++){
if(a[i]!=mx) break;
if(i==n){
cout<<"No\n";
return;
}
}
cout<<"Yes\n";
for(int i=1;i<=n;i++){
if(i!=idx) cout<<1<<" ";
else cout<<2<<" ";
}
cout<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--){
solve();
}
return 0;
}
B. Apples in Boxes
奇奇妙妙博弈题
在特判条件上卡了半小时,真不应该
最大值mx,最小值mn。
如果 mx - mn 的值 > k+1 ,则第一个人必输。
如果 mx - mn 的值 == k+1 ,且有多个mx值,则第一个人必输,因为就算让一个mx-1,也有其他mx让第一个人输。
否则就是一个奇偶博弈。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
//using i128 = __int128_t;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n,k;
cin>>n>>k;
int sum=0;
vector<int> a(n+1);
for(int i=1;i<=n;i++){
cin>>a[i];
sum+=a[i];
}
int mx=*max_element(a.begin()+1,a.end());
int mn=*min_element(a.begin()+1,a.end());
int cnt=0;
for(int i=1;i<=n;i++){
if(a[i]==mx) cnt++;
}
if(mx-mn>k+1){
cout<<"Jerry"<<endl;
return;
}
if(mx-mn==k+1 && cnt>1){
cout<<"Jerry"<<endl;
return;
}
if(sum&1){
cout<<"Tom";
}else{
cout<<"Jerry";
}
cout<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--){
solve();
}
return 0;
}
C. Maximum Subarray Sum
赛时想复杂了,其实很简单一题,最后几分钟多写了一个错误的判断条件,wa了。
首先先把所有缺失的地方赋值成 -inf.
跑一边dp,对每个被-inf分割的块计算最大子数组和。令最大值为 t
如果t>k,则无解
如果t==k,则直接输出数组即可
如果t<k,则随便找一个-inf,位置是pos,把这个-inf和改成某个值,使得t=k即可。
如何计算改成的值?
需要知道:
从前往后算以每个位置的为结尾的最大子数组和dp[i]
从后往前算以每个位置的为结尾的最大子数组和idp[i]
这个值 == k- ( max(0, dp[i-1]) + max(0,idp[i+1]) )
最后所有地方都不缺值,则无解。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
//using i128 = __int128_t;
const ll inf = 100'000'000'000'000'000;
const int mod = 998244353;
void solve(){
int n,k;
cin>>n>>k;
string s;
cin>>s;
s=" "+s;
int ans=0;
vector<int> a(n+10),dp(n+10),f(n+10),idp(n+10);
for(int i=1;i<=n;i++){
cin>>a[i];
if(s[i]=='1') f[i]=1;
if(f[i]==0) a[i]=-inf;
}
for(int i=1;i<=n;i++){
dp[i]=a[i];
dp[i]=max(dp[i],a[i]+dp[i-1]);
ans=max(ans,dp[i]);
}
if(ans>k){
cout<<"No\n";
return;
}
else if(ans==k){
cout<<"Yes\n";
for(int i=1;i<=n;i++){
cout<<a[i]<<" ";
}
cout<<endl;
return;
}
//ans<k
for(int i=n;i>=1;i--){
idp[i]=a[i];
idp[i]=max(idp[i],a[i]+idp[i+1]);
}
for(int i=1;i<=n;i++){
if(f[i]==1) continue;
int t1=max(0ll,dp[i-1]);
int t2=max(0ll,idp[i+1]);
a[i]=k-(t1+t2);
cout<<"Yes\n";
for(int j=1;j<=n;j++){
cout<<a[j]<<" ";
}
cout<<endl;
return;
}
cout<<"No\n";
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--){
solve();
}
return 0;
}
D. Apple Tree Traversing
显然是找树的直径 -> 删直径 -> 找直径 循环。
复杂度是n*sqrtn
找到一条直径并删除后,剩下的节点被分为很多个不联通的块,分治每个块即可。
点击查看代码
#include<bits/stdc++.h>
// #define int long long
using namespace std;
using pii=pair<int,int>;
using ll=long long;
const ll inf=1e18;
const int mod =1e9+7;
void solve(){
int n;
cin>>n;
vector<vector<int>> g(n+1);
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
vector<int> vis(n+1);
vector<array<int,3>> ans;
vector<int> fa(n+1),dep(n+1);
auto work=[&](auto work,int now)->void {
vector<int> a;//以now为根节点,能走到的节点
auto dfs=[&](auto dfs,int u,int pre)->void {
dep[u]=dep[pre]+1;
fa[u]=pre;
a.push_back(u);
for(auto v:g[u]){
if(vis[v] || v==pre) continue;
dfs(dfs,v,u);
}
};
dfs(dfs,now,0);
int rt1=0,rt2=0;
for(auto u:a){
if(dep[u]>dep[rt1]) rt1=u;
else if(dep[u]==dep[rt1]) rt1=max(rt1,u);
}
dfs(dfs,rt1,0);
for(auto u:a){
if(dep[u]>dep[rt2]) rt2=u;
else if(dep[u]==dep[rt2]) rt2=max(rt2,u);
}
int cnt=0, tmp=rt2;
while(tmp!=0){
vis[tmp]=1;
cnt++;
tmp=fa[tmp];
}
ans.push_back({cnt, max(rt1,rt2),min(rt1,rt2)});
for(auto u:a){
if(vis[u]) continue;
work(work,u);
}
};
work(work,1);
sort(ans.begin(),ans.end(),greater<>());
for(auto [a,b,c]:ans){
cout<<a<<" "<<b<<" "<<c<<" ";
}
cout<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--){
solve();
}
return 0;
}
E. Ain and Apple Tree
学的洛谷题解第一篇
就这种构造题赛时见到包做不出来
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll=long long;
const ll inf=1e18;
const int mod =1e9+7;
void solve(){
int n,k;
cin>>n>>k;
vector<int> a;
for(int i=n-1;i>=1;i--){
int val=i*(i-1)/2;
if(k>=val){
k-=val;
a.push_back(i);
}
}
if(k>1){
cout<<"No\n";
return;
}
cout<<"Yes\n";
int now=1,cnt=1,sum=n;
for(auto val:a){
for(int i=1;i<=sum-val;i++){
cout<<now<<" "<<++cnt<<endl;
}
sum=val;
now=cnt;
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--){
solve();
}
return 0;
}
F1. Cycling (Easy Version)
范围是5000,考虑n^2的dp
设f[i]表示从i后面跳到0的最小代价,初始f[0]=0;
对每个i,枚举j:(0,i-1),表示从i后面跳到j后面,再跳到0
每次跳跃,用区间(j+1,i)内的最小值跳到j后面
设最小值val的位置pos,则f[i]=min: f[j]+i-pos+val*(i-j)+i-j-1
i-pos: 把val从pos换到位置i的代价
val*(i-j): 每次跨过val的代价
i-j-1: 每次把val往前交换一次的代价
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll=long long;
const ll inf=1e18;
const int mod =1e9+7;
/*
设f[i]表示从i后面跳到0的最小代价,初始f[0]=0;
对每个i,枚举j:(0,i-1),表示从i后面跳到j后面,再跳到0
每次跳跃,用区间(j+1,i)内的最小值跳到j后面
设最小值val的位置pos,则f[i]=min: f[j]+i-pos+val*(i-j)+i-j-1
i-pos: 把val从pos换到位置i的代价
val*(i-j): 每次跨过val的代价
i-j-1: 每次把val往前交换一次的代价
*/
void solve(){
int n;
cin>>n;
vector<int> a(n+10,inf),f(n+10,inf);
for(int i=1;i<=n;i++){
cin>>a[i];
}
f[0]=0;
for(int i=1;i<=n;i++){
int val=inf,pos=0;
for(int j=i-1;j>=0;j--){
if(a[j+1]<val){
pos=j+1;
val=a[j+1];
}
f[i]=min(f[i],f[j]+i-pos+val*(i-j)+i-j-1);
}
}
cout<<f[n]<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--){
solve();
}
return 0;
}

浙公网安备 33010602011771号