AtCoder Grand Contest 025

链接

D. Choosing Points

考虑如果只有 \(\sqrt D\),可以由于发现 \(x^2+y^2=D\) 的所有解中 \(x+y\) 的奇偶性相同,所以连成的图是一张二分图。

二分图的最大独立子集显然大于等于点数一半。

那么两张二分图的最大独立子集显然大于等于点数的 \(\frac 14\)。直接枚举是哪一边的点集即可。复杂度 \(O(n^2)\)

E. Walking on a Tree

官网题解做法:

考虑每次取一个叶子,如果这个叶子上只有一条路径,那么这个叶子可以不用管,路径的起点顺延到它的父亲。否则考虑任意取两条路径 \(u\rightarrow a,u\rightarrow b\),考虑他们的交 \(u\rightarrow c\),显然交部分就是 \(2\),剩余部分等价于一条 \(a\rightarrow b\) 的路径。

最后返回去构造初始路径。

神仙做法

考虑如果存在当前只剩下一条路径的点,并且只被单向经过过一次,那么这条路径必须以另一方向经过。

否则说明所有路径都至少有两条路径,随便构造即可。

复杂度 \(O(n^2)\)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define N 4010
#define fi first
#define se second
#define MP make_pair
using namespace std;
typedef pair<int,int> P;
int x[N],y[N];
vector<P>g[N];
int dep[N],fa[N],rf[N];
void dfs(int u,int p)
{
    fa[u]=p;dep[u]=dep[p]+1;
    for(auto &[v,w]:g[u]) if(v!=p) rf[v]=w,dfs(v,u);
}
void get(int x,int y,vector<int>&w)
{
    for(;dep[x]>dep[y];x=fa[x]) w.push_back(rf[x]^1);
    for(;dep[y]>dep[x];y=fa[y]) w.push_back(rf[y]);
    for(;x!=y;x=fa[x],y=fa[y]) w.push_back(rf[x]^1),w.push_back(rf[y]);
}
vector<int>p[N],id[N];int deg[N],vis[N],op[N];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),g[u].push_back(MP(v,2*i)),g[v].push_back(MP(u,2*i+1));
    dfs(1,0);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x[i],&y[i]);
        get(x[i],y[i],p[i]);
        for(int v:p[i]) id[v/2].push_back(i),deg[v/2]++/*,printf("- %d ",v);puts("")*/;
    }
    long long ans=0;
    for(int i=1;i<n;i++) ans+=min(2,deg[i]);
    printf("%lld\n",ans);
    while(true)
    {
        int u=0,w=0;
        for(int i=1;i<n;i++) if(deg[i]==1 && op[i*2]!=op[i*2+1]){w=i;break;}
        if(!w) for(int i=1;i<n;i++) if(deg[i]>=2){w=i;break;}
        if(!w) break;
        for(int v:id[w]) if(!vis[v]){u=v;break;}
        vis[u]=true;
        for(int v:p[u]) if(v/2==w)
        {
            if(op[v]) swap(x[u],y[u]),for_each(p[u].begin(),p[u].end(),[&](int &x){x^=1;});
            for_each(p[u].begin(),p[u].end(),[&](int &x){deg[x/2]--,op[x]=true;});
        }
    }
    for(int i=1;i<=m;i++) printf("%d %d\n",x[i],y[i]);
    return 0;
}
posted @ 2023-09-20 18:56  Flying2018  阅读(18)  评论(0)    收藏  举报