CF2040D题解

CF2040D题解

神奇构造题,感觉自己想到了一丢丢,但是没有往正解的方向去想。

题意

给出一张 \(n\) 个节点的树,从 \(1-2n\) 中最多每个数选一次填到树中,求一种任意两个节点权值之差都不是质数的填数方案。

分析

比赛的时候考虑到了 \(1-2n\) 这个特殊条件,可以考虑只用偶数或者是奇数,假设是只用 \(2,4,6,8...,2n\) 的话,。

首先想到的是奇偶染色,然后分别把 \(2,6,10...(A)\)\(4,8,12..(B)\) 填到不同颜色中。

然后发现这样全是不合法,所以把这种想法叉掉了。。。。

我们发现实际上就可以从这个角度来思考,先考虑给这个树分层,既然刚刚都顺着填的思路是很错误的,那我们反过来,用一个 Meet in

the middle 的思路来进行染色。

也就是根据 bfs 序和层数的奇偶性来进行填充,对于所有奇数层,我们把 \(2,4,6,8..\) 按顺序填进去;对于 所有的偶数层,我们把 \(2n,2n-2,2n-4...\) 按照顺序填进去,这样一定最后填完的时候不会重,并且大体上都是合法的,因为所有的相邻差都是偶数,并且基本上都不是 \(2\)。那么什么地方会是 \(2\) 呢?肯定就是我们最后meet的地方,而且它一定在叶节点,并且只有这一个不合法的地方,我们直接对他进行 \(+-1\) 就可以了。

Code

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int T,n;
inline void solve()
{
    cin>>n;
    vector<int> e[n+2],a(n+1,0),isf(n+1,0);
    vector<vector<int>>num(2,vector<int>(n+2,0));
    for(int i=1;i<=n;++i)num[0][i]=i<<1,num[1][i]=(n-i+1)<<1;
    for(int i=1,u,v;i<n;++i)
    {
        cin>>u>>v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    queue<pair<int,int>> q;
    int cnt[2]={0,0};
    q.push({1,0});
    while(q.size())
    {
        int x=q.front().first,type=q.front().second;
        q.pop();
        a[x]=num[type][++cnt[type]];
        for(auto v:e[x])
        {
            if(a[v])continue;
            isf[x]=1;
            q.push({v,type^1});
        }
    }
    for(int i=1;i<=n;++i)
    {
        if(isf[i])continue;
        for(auto v:e[i])
        {
            if(abs(a[i]-a[v])==2)
            {
                if(a[i]>a[v])a[i]--;
                else a[i]++;
                goto OUTPUT;
            }
        }
    }
    OUTPUT:;
    for(int i=1;i<=n;++i)cout<<a[i]<<' ';
    cout<<'\n';
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>T;
    while(T--)
    {
        solve();
    }
    return 0;
}	

另一种解

这种奇怪构造应该可乱搞性挺高的,根据starsilk的说法,好像可以特判菊花,然后还是只用偶数,找到一条长度为 \(4\) 的链,然后根据奇偶染色的原理也可以做。

不过我不太懂。

总结

构造题可以先构造出一种大体合法的方案,然后对于不合法的细节进行微调。

posted @ 2024-12-10 00:02  Hanggoash  阅读(1)  评论(0编辑  收藏  举报
动态线条
动态线条end