CF1856(Codeforces Round 890 (Div. 2))

总结

\(t1\) 看起来好简单啊,\(5min\) 切了。
\(t2\) 看起来好简单啊,\(15min\) 切了。
\(t3\) 看起来好难啊,\(50min\) 跳了。
一开始想到了二分答案,迟迟想不到 \(O(n)\)\(check\),于是思维开始发散,从贪心想到 \(dp\)
考完发现大家都是 \(O(n^2)\)\(check\),wssb。
\(t4\) 是道交互,直接跳了。
\(t5\) 看起来还行,让我做做。
\(after\ 1\ hour......\)
还是没想出来,还差一个 \(dp\) 就想出来了,但就是抓不到方程。。。
比赛结束前 \(5min\) 想到了做法,可惜大势已去。。。
只做出来两道题,太惨了。
实力太菜导致的。
(考后两分钟交了 \(t5\)\(AC\)

解析

A. Tales of a Sort

难度:红
简单题。


#include<bits/stdc++.h>
#define mxn 55
#define ll long long
using namespace std;
ll t,n,a[mxn],ans;
void solve(){
    cin>>n;ans=0;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<n;i++)
        if(a[i]>a[i+1])ans=max(ans,a[i]);
    cout<<ans<<'\n';
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>t;while(t--)solve();
    return 0;
}

B. Good Arrays

难度:橙
如果不是 \(1\) 对其他数的贡献为 \(a_i-1\),是 \(1\) 贡献为 \(-1\)
最后判断贡献是否 \(<0\) 就行了。


#include<bits/stdc++.h>
#define mxn 100010
#define ll long long
using namespace std;
ll t,n,a[mxn],sum;
void solve(){
    cin>>n;sum=0;
    for(int i=1;i<=n;i++)cin>>a[i];
    if(n==1){cout<<"NO\n";return;}
    for(int i=1;i<=n;i++){
        if(a[i]==1)sum--;
        else sum+=a[i]-1;
    }
    if(sum<0)cout<<"NO\n";
    else cout<<"YES\n";
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>t;while(t--)solve();
    return 0;
}

C. To Become Max

难度:黄-绿
想着用二分,结果 \(O(n)\)\(check\),结果很久都没写出来,玉玉了。
打完才发现 \(check\) 是可以 \(O(n^2)\) 的。


#include<bits/stdc++.h>
#define mxn 1010
#define ll long long
using namespace std;
ll n,k,t,a[mxn];
ll l,r,ans;
ll tot,b[mxn];
bool flg=1;
bool check(ll x){
    if(a[n]>=x)return 1;
    for(int i=1;i<n;i++){
        if(a[i]>=x)return 1;
        tot=k,flg=1;
        for(int j=1;j<=n;j++)b[j]=a[j];
        tot-=x-b[i],b[i]=x;
        if(tot<0)continue;
        for(int j=i+1;j<n;j++){
            if(b[j]>=b[j-1]-1)return 1;
            tot-=(b[j-1]-1)-b[j];
            b[j]=b[j-1]-1;
            if(tot<0){
                flg=0;break;
            }
        }
        if(flg&&b[n]>=b[n-1]-1)return 1;
    }
    return 0;
}
void solve(){
    cin>>n>>k;
    for(int i=1;i<=n;i++)cin>>a[i];
    l=1,r=1e12;
    while(l<=r){
        ll mid=(l+r)>>1;
        if(check(mid))ans=mid,l=mid+1;
        else r=mid-1;
    }
    cout<<ans<<'\n';
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>t;while(t--)solve();
    return 0;
}

D. More Wrong

难度:绿
发掘一下最大值的性质!如果最大值位置为 \(p\),则有 \(ask(l,p)=ask(l,p-1)\)
因为找不到比 \(a_p\) 更大的数了。
所以可以分治查找。复杂度 \(O(4n^2)\)


#include<bits/stdc++.h>
#define mxn 5010
#define pb push_back
using namespace std;
int n,t;
int ask(int l,int r){
    cout<<"? "<<l<<' '<<r<<endl;
    int ret;cin>>ret;return ret;
}
int dfs(int l,int r){
    if(l==r)return l;
    if(l==r-1)return ask(l,r)?l:r;
    int mid=(l+r)>>1,x=dfs(l,mid),y=dfs(mid+1,r);
    if(ask(l,y-1)==ask(l,y))return y;
    else return x;
}
void solve(){
    cin>>n;
    int ans=dfs(1,n);
    cout<<"! "<<ans<<endl;
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>t;while(t--)solve();
    return 0;
}

E1. PermuTree (easy version)

难度:绿
题目转化一下:在以 \(i\) 为根的树下选取若干子树分成两部分,使子树大小的和的乘积最大。
数据较小的时候直接暴力背包就行了。


#include<bits/stdc++.h>
#define mxn 5010
#define pb push_back
#define ll long long
using namespace std;
ll n,k,a[mxn];
ll dp[mxn],sze[mxn],ans;
vector<int> t[mxn];
void solve(){
    cin>>n>>k;
    for(int i=1;i<=n;i++)cin>>a[i];
}
void dfs1(int u,int f){
    sze[u]=1;
    for(int i=0;i<t[u].size();i++){
        int v=t[u][i];
        if(v==f)continue;
        dfs1(v,u);
        sze[u]+=sze[v];
    }
    return;
}
void dfs2(int u,int f){
    ll cnt=0,sum=0,maxn=0,vis[mxn]={0};
    vis[0]=1;
    for(int i=0;i<t[u].size();i++){
        int v=t[u][i];
        if(v==f)continue;
        dfs2(v,u);
        for(int j=sze[u];j>=0;j--)
            if(vis[j]){
                vis[j+sze[v]]=1;
                maxn=max(maxn,(j+sze[v])*(sze[u]-1-j-sze[v]));
            }
    }
    ans+=maxn;
    return;
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n;
    for(int i=1+1;i<=n;i++){
        int v;cin>>v;
        t[i].pb(v),t[v].pb(i);
    }
    dfs1(1,0);
    dfs2(1,0);
    cout<<ans;
    return 0;
}

E2. PermuTree (hard version)

难度:紫
我们发现,求出时间复杂度的瓶颈在于:
把儿子大小构成的数集合分成差尽可能小的两部分。
对于这里的优化,有很多做法,如 \(FFT\)\(bitset\),这里选择 \(bitset\) 的做法。

首先,若 \(sze_v\geq\frac{1}{2}sze_u\),直接返回 \(sze_v*(sze_u-sze_v-1)\) 就行了,这里不解释。
剩下的就是一个二进制优化完全背包,由于时限和动态大小,所以这里要手写 \(bitset\)
懒得写了,抛个soluion代码。


// #pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
#include<bits/stdc++.h>
#define ll long long
#define mxn 1000010
using namespace std;
int n; 
vector<int> e[mxn];
int siz[mxn];
int cnt[mxn];
unsigned ll vis[(mxn>>6)+10];
void lshift(int n,int x){
	if((x&63)==0){
		for(int i=n;i>=(x>>6);--i) 
            vis[i]|=vis[i-(x>>6)];
	}
	else{
		for(int i=n;i>=(x>>6);--i){
			int wzl=(i<<6)-x;
			vis[i]|=(wzl<0?0:vis[wzl>>6]>>(wzl&63))|(vis[(wzl>>6)+1]<<(64-(wzl&63)));
		}
	}
}
ll ans=0;
void dfs(int u){
	siz[u]=1;
	int ax=0;
	for(int v:e[u]){ 
        dfs(v);
        siz[u]+=siz[v];
        ax=max(ax,siz[v]);
    }
	if(ax*2>=siz[u]-1) 
        ans+=1ll*ax*(siz[u]-1-ax);
	else{
		for(int v:e[u]) 
            ++cnt[siz[v]];
		memset(vis,0,((siz[u]-1>>6)+5)*8);
		vis[0]=1;
		for(int v:e[u]){
			if(cnt[siz[v]]==0)continue;
			int now=1;
			while(now<=cnt[siz[v]]){
				lshift(siz[u]-1>>6,siz[v]*now);
				cnt[siz[v]]-=now,now<<=1;
			}
			if(cnt[siz[v]]!=0) 
                lshift(siz[u]-1>>6,siz[v]*cnt[siz[v]]);
			cnt[siz[v]]=0;
		}
		int mid=(siz[u]-1)/2;
		for(int i=0;;++i){
			if(vis[mid+i>>6]>>(mid+i&63)&1){ 
                ans+=1ll*(mid+i)*(siz[u]-1-mid-i); 
                break; 
            }
			if(vis[mid-i>>6]>>(mid-i&63)&1){ 
                ans+=1ll*(mid-i)*(siz[u]-1-mid+i);
                break; 
            }
		}
	}
}
int main(){
	ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=2;i<=n;++i){
		int f;cin>>f;
		e[f].push_back(i);
	}
	dfs(1);
	cout<<ans;
	return 0;
}
posted @ 2024-11-02 16:09  nagato__yuki  阅读(47)  评论(0)    收藏  举报