CF1981D题解

CF1981D题解

前言

标签:筛法,欧拉回路

赛后过的,构造一眼秒,欧拉图写错了,多少有点抽象。

题意

构造一个长度为 \(n\) 的序列 \(a\),需要满足:

  • \(\forall 1 \le i \le n,1 \le a_i \le 3\times10^5\)

  • \(\forall 1 \le i<j<n,a_i\times a_{i+1}\ne a_j\times a_{j+1}\)

分析

发现任意两个质数的乘积是唯一的,而 \(\max_{1\le i\le 3\times 10^5}\{d(i)^2\} \le 10^6\)

所以显然只需要选 \(m\) 个质数。

而现在就是要构造一个长度为 \(n\) 的序列使得每一对无序数对 \(\{a_i,a_{i+1}\}\) 都不同。

因为构造方式是从一个数开始,走到另一个数,和路径是一样的,所以考虑构造一个无向完全图(带自环),然后找最长路径。

\(m\) 是奇数时,每个点的度一定是偶数,所以直接跑欧拉回路,序列长度为 \(\frac{m\times (m+1)}{2}+1\)

\(m\) 是偶数,每个点的度一定是奇数,我们可以删除所有形如 \(\{3,4\},\{5,6\},\dots,\{n-1,n\}\) 的边,这样就剩下了两个奇点,直接跑欧拉回路,序列长度为 \(\frac{m\times (m+1)}{2}-\frac{m-2}{2}+1\)

直接枚举求 \(m\) 即可。

代码

建图用了 bitset

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    char ch=getchar();int x=0;bool f=1;
    while(ch<'0'||'9'<ch){if(ch=='-')f=0;ch=getchar();}
    while('0'<=ch&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return f?x:-x;
}
const int N=3e5+2;
int cnt,prime[N];
bool is_p[N];
void init(int n){
    for(int i=2;i<=n;i++){
        if(!is_p[i])prime[++cnt]=i;
        for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
            is_p[i*prime[j]]=1;
            if(!(i%prime[j]))break;
        }
    }
}
const int M=1500;
int n,m;
bitset<M>vis[M];
stack<int>st;
void dfs(int u){
    if(vis[u][u])vis[u][u]=0,dfs(u);
    for(int i=vis[u]._Find_first();i<=m;i=vis[u]._Find_first())
        if(vis[u][i])
            vis[u][i]=vis[i][u]=0,dfs(i);
    st.push(prime[u]);//注意要最后加点,不然跑出来的不是欧拉回路,笔者栽在这里了
}
void Main(){
    n=read();
    if(n==1)return puts("1"),void();
    for(m=1;(m*(m+1)/2)-((m&1)?0ll:((m>>1)-1))<n-1;m++);
    for(int i=1;i<=m;i++)
        vis[i].set();
    if(!(m&1))
        for(int i=3;i<=m;i+=2)vis[i][i+1]=vis[i+1][i]=0;
    dfs(1);
    while(!st.empty()&&n)printf("%d ",st.top()),st.pop(),n--;
    while(!st.empty())st.pop();
    puts("");
    return;
}
signed main(){
    init(13000);
    int T=read();
    while(T--)Main();
    return 0;
}
posted @ 2024-05-31 21:31  sunzz3183  阅读(13)  评论(0编辑  收藏  举报
Live2D