CF2019
A.Max Plus Size
难度:红
弱智题。
奇数偶数分别判一遍。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll T,n,a[110],dp[110][110][2],ans1,ans2;
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>T;
while(T--){
cin>>n;
ans1=ans2=0;
for(int i=1;i<=n;i++){
cin>>a[i];
if(i%2==1)ans1=max(ans1,a[i]);
if(i%2==0)ans2=max(ans2,a[i]);
}
cout<<max(ans1+(n+1)/2,ans2+(n/2))<<'\n';
}
return 0;
}
B.All Pairs Segments
难度:橙
有点弱智题。
每个点计算贡献然后用一个map存起来。
#include<bits/stdc++.h>
#define ll long long
#define mxn 100010
using namespace std;
ll T,n,q,a[mxn];
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>T;
while(T--){
map<ll,ll> mp;
cin>>n>>q;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++){
ll b=i*(n-i+1)-1;
mp[b]++;
if(i<n&&a[i+1]-a[i]>1){
b=i*(n-i);
mp[b]+=a[i+1]-a[i]-1;
}
}
for(int i=1;i<=q;i++){
ll b;
cin>>b;
cout<<mp[b]<<' ';
}
cout<<'\n';
}
return 0;
}
C.Cards Partition
难度:黄
从 \(n\) 到 \(1\) 枚举,存在方案就输出。
#include<bits/stdc++.h>
#define ll long long
#define mxn 200010
using namespace std;
ll T,n,k,sum,mxa,a[mxn];
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>T;
while(T--){
cin>>n>>k;
sum=mxa=0;
for(int i=1;i<=n;i++){
cin>>a[i];
sum+=a[i];
mxa=max(mxa,a[i]);
}
for(int i=n;i;i--){
if((sum+k)/i>=mxa&&(i-sum%i)%i<=k){
cout<<i<<'\n';
break;
}
}
}
return 0;
}
D.Speedbreaker
难度:黄
主要是一个区间交集存在性问题。考虑把 \([i-a[i]+1,i+a[i]-1]\) 当作一个区间。
#include<bits/stdc++.h>
#define ll long long
#define mxn 200010
using namespace std;
ll t,n,a[mxn],l[mxn],r[mxn];
void solve(){
cin>>n;
for(int i=1;i<=n;i++)
l[i]=n+1,r[i]=0;
for(int i=1;i<=n;i++){
cin>>a[i];
l[a[i]]=min(l[a[i]],i*1ll);
r[a[i]]=max(r[a[i]],i*1ll);
}
ll maxn=0,minn=n+1,lans=0,rans=n+1;
bool flg=1;
for(int i=1;i<=n;i++){
if(!r[i])continue;
minn=min(minn,l[i]);
maxn=max(maxn,r[i]);
if(maxn-minn>i-1)flg=0;
if(rans<r[i]-i+1||lans>l[i]+i-1)flg=0;
lans=max(lans,r[i]-i+1);
rans=min(rans,l[i]+i-1);
}
if(flg)cout<<rans-lans+1<<'\n';
else cout<<0<<'\n';
return;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>t;
while(t--)solve();
return 0;
}
E.Tree Pruning
难度:黄-绿
机房巨佬说这题用虚树直接秒了。可蒟蒻连虚树是什么都不知道qwq
枚举每一个修剪到的深度,然后取最小值。如果是直接暴力的话时间复杂度 \(O(n^2)\),显然会炸。
设 \(mxdep_i\) 为每个点能到达的最大深度,\(dep_i\) 为每个点深度。于是每个点会在 \(dep_i\sim mxdep_i\) 处产生贡献。考虑前缀和优化。
#include<bits/stdc++.h>
#define ll long long
#define mxn 500010
using namespace std;
ll n,sum[mxn],dep[mxn],mxdep[mxn],ans;
vector<int> t[mxn];
void dfs(int u,int f){
dep[u]=mxdep[u]=dep[f]+1;
for(int i=0;i<t[u].size();i++){
int v=t[u][i];
if(v==f)continue;
dfs(v,u);
mxdep[u]=max(mxdep[u],mxdep[v]);
}
return;
}
void init(){
ans=0;
for(int i=1;i<=n;i++){
t[i].clear();
sum[i]=dep[i]=mxdep[i]=0;
}
return;
}
void solve(){
cin>>n;
init();
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
t[u].push_back(v);
t[v].push_back(u);
}
dfs(1,0);
for(int i=1;i<=n;i++)
sum[dep[i]]++,sum[mxdep[i]+1]--;
for(int i=1;i<=n;i++){
sum[i]+=sum[i-1];
ans=max(ans,sum[i]);
}
cout<<n-ans<<'\n';
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int t;
cin>>t;
while(t--)
solve();
return 0;
}
F.Max Plus Min Plus Size
难度:蓝-紫
第一题的...加强版?
首先,最大值一定为 \(a[n]\)。不然可以把 \(a[n]\) 旁边的删掉选 \(a[n]\)。
然后考虑从大到小枚举最小值。在每一次枚举完后打个标记,若两边的数标记过就用并查集合并。
注意最大值可能在合并的连通块中,需要用奇偶性判断。
#include<bits/stdc++.h>
#define ll long long
#define mxn 200010
#define pii pair<int,int>
using namespace std;
ll T,n,f[mxn],st[mxn],sze[mxn];
ll jo[mxn][2],sum,ans,ok,vis[mxn];
pii a[mxn];
int fnd(int x){
if(x==f[x])return x;
return f[x]=fnd(f[x]);
}
int pd(int x){
if(sze[x]%2==0){
if(jo[x][0]||jo[x][1])return 1;
else return 0;
}
else{
if(st[x]%2==1){
if(jo[x][1])return 1;
else return 0;
}
else{
if(jo[x][0])return 1;
return 0;
}
}
return 0;
}
void merge(int x,int y){
int fx=fnd(x),fy=fnd(y);
if(fx!=fy){
sum-=(sze[fx]+1)/2+(sze[fy]+1)/2;
ok-=pd(fx)+pd(fy);
st[fx]=min(st[fx],st[fy]);
jo[fx][0]|=jo[fy][0];
jo[fx][1]|=jo[fy][1];
sze[fx]+=sze[fy];
sum+=(sze[fx]+1)/2;
ok+=pd(fx);
f[fy]=fx;
}
return;
}
void solve(){
cin>>n;
for(int i=1;i<=n+1;i++){
f[i]=st[i]=i,sze[i]=1;
jo[i][0]=jo[i][1]=0;
vis[i]=0;
}
sum=ans=ok=0;
for(int i=1;i<=n;i++){
cin>>a[i].first;
a[i].second=i;
}
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)
if(a[i].first==a[n].first)
jo[a[i].second][a[i].second&1]=1;
for(int i=n;i;i--){
int j=i;
while(j&&a[j].first==a[i].first){//最大值必为a[n],枚举最小值
int id=a[j].second;
vis[id]=1;
sum++;
if(jo[id][0]||jo[id][1])ok++;
if(vis[id-1])merge(id,id-1);
if(vis[id+1])merge(id,id+1);
ans=max(ans,a[n].first+a[i].first+sum-(ok<=0));
j--;
}
i=j+1;
}
cout<<ans<<'\n';
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>T;
while(T--)solve();
return 0;
}
标签:return,int,ll,long,mxn,fx,CF2019
From: https://www.cnblogs.com/nagato--yuki/p/18437085