CSP 模拟 7

T1 Permutations & Primes

\(2,3\) 放两边,\(1\),放中间,易证最优。

T2 树上游戏

原题 [ARC116E] Spread of Information
二分是明显的,关键在 check,发现每次选最深的叶子节点的 \(mid\) 级父亲一定不劣,因为它能够覆盖最多。然后每次找就行,实现比较麻烦。
\(f_i\) 表示 \(i\) 的子树内最远未被覆盖的点的距离,\(g_i\) 表示 \(i\) 的子树内最近是关键点的距离。初值 \(f\) 负无穷,表示被覆盖,\(g\) 正无穷,表示还没有关键点。然后分讨进行转移。

点击查看代码
#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
inline int read(){char ch=getchar();int x=0,f=1;for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);return x*f;}
const int N=2e5+10;
int n,k,mid,res=0,f[N],g[N],dep[N];
std::vector<int> e[N];
bool vis[N];
inline void dfs(int u,int fa){
	f[u]=-N,g[u]=N;
    for(int v:e[u]){
    	if(v==fa)continue;
    	dfs(v,u);
    	f[u]=std::max(f[u],f[v]+1);
    	g[u]=std::min(g[u],g[v]+1);
    }
   	if(f[u]+g[u]<=mid)f[u]=-N;
   	if(g[u]>mid){
   		f[u]=std::max(f[u],0);
   	}
   	if(f[u]==mid){
   		f[u]=-N,g[u]=0,++res;
   	}
}
signed main(){
	// freopen("in.in","r",stdin);freopen("out.out","w",stdout);
	std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
	n=read(),k=read();
	for(int i=2;i<=n;++i){int u=read(),v=read();e[u].emplace_back(v);e[v].emplace_back(u);}
    int l=1,r=n,ans=0;
	r=n/k+1;
    while(l<=r){
        mid=l+r>>1;
        res=0;
        dfs(1,0);
        res+=f[1]>=0;
        if(res<=k)ans=mid,r=mid-1;
        else l=mid+1;
    }   
    std::cout<<ans<<'\n';
}
  • \(f_i+g_i\le mid\) 表示这个点子树内的可以全覆盖,不需要进行覆盖。\(f_i=-inf\)
  • \(g_i>mid\) 时,不呢覆盖当前节点,需要父亲来覆盖,\(f_i=\max(f_i,0)\)
  • \(f_i=mid\) 是,这个点不得不覆盖了,\(f_i=-inf,g_i=0\),答案加一。
    对于最后的根节点,需要查看是否覆盖来增加答案。

T3 Ball Collector

原题 [ABC302Ex] Ball Collector
自然想到颜色连边,然后发现连成一棵树(\(n-1\) 条边,无自环)时可以拿到 \(n-1\) 种颜色,否则可以拿到 \(n\) 种颜色。
因为我们是按照边拿,对于树的话,从叶子开始拿最大,根节点拿不了,所以是 \(n-1\) 种颜色。
如果有环的话,就可以少贡献一条边,从而全拿。
知道这个之后就直接上可撤销并查集维护图的形态即可,因为要维护图的具体形态,所以不能路径压缩。

点击查看代码
#include<bits/stdc++.h>
#define int long long
typedef long long ll;
typedef unsigned long long ull;
inline int read(){char ch=getchar();int x=0,f=1;for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);return x*f;}
const int N=4e5+10;
int n,a[N],b[N],dep[N],ANS[N],ans,num[N],size[N],tag[N],top,fa[N];
std::pair<int,int> st[N<<1];
std::vector<int> e[N];
inline int find(int x){return fa[x]==x?x:find(fa[x]);}
inline void add(int x,int y){
    x=find(x);y=find(y);top++;
    if(x==y){
        if(num[x]==size[x]-1)ans++,tag[top]=1;
        num[x]++,st[top]={-1,x};
    }else{
        if(size[x]>size[y])std::swap(x,y);
        if(num[x]==size[x]-1||num[y]==size[y]-1)ans++,tag[top]=1;
        size[y]+=size[x];fa[x]=y;st[top]={x,y};
        num[y]+=num[x]+1;
    }
}
inline void del(int id){
    if(st[id].first==-1)num[st[id].second]--;
    else{int x=st[id].first,y=st[id].second;fa[x]=x;size[y]-=size[x];num[y]-=num[x]+1;}
    if(tag[id])ans--;
    tag[id]=0;st[id]={0,0};
}
inline void dfs(int u,int fa){
    int cur=top;
    add(a[u],b[u]);
    ANS[u]=ans;
    for(int v:e[u])if(v!=fa)dfs(v,u);
    while(top>cur)del(top--);
}
signed main(){
    // freopen("in.in","r",stdin);freopen("out.out","w",stdout);
    std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
    n=read();
    for(int i=1;i<=n;++i)a[i]=read(),b[i]=read();
    for(int i=2;i<=n;++i){
        int u=read(),v=read();
        e[u].emplace_back(v);e[v].emplace_back(u);
    }
    for(int i=1;i<=n;++i)size[i]=1,fa[i]=i;
    dfs(1,0);
    for(int i=2;i<=n;++i)std::cout<<ANS[i]<<' ';
}

T4 满穗

不会。

posted @ 2024-07-28 07:27  Ishar-zdl  阅读(39)  评论(0)    收藏  举报