题解:CF1270G Subset with Zero Sum

前言

感觉题目条件明示做法,并加深了我对 CF 的本质是 PH 的刻板印象。

思路分析

因为不小心看见了标签有 graph,所以断定这是一道图论建模题。

然后发现有限制 \(a_i\in[i-n,i-1]\),发现这个是一个长度为 \(n\) 的区间,我们希望把它映射到 \([1,n]\),发现 \(i-a_i\in[1,n]\)

对着这个东西仔细研究,发现如果连边 \(i \to i-a_i\),那么和为 \(0\) 的集合,就是图上的一个环。

考虑证明。

对于 \(p_1\to p_2\to \cdots\to p_k\to p_1\) 的环,满足:

\[p_k=p_1-\sum_{i=1}^{k-1}a_i \]

\[p_1=p_k-a_k \]

解得:

\[\sum_{i=1}^{k} a_i=0 \]

真是一个绝妙的猜测构造!

代码实现

#include<bits/stdc++.h>
using namespace std;
int t,n,a[1000005],vis1[1000005],vis2[1000005],flag;
stack<int> s;
int head[1000005],nxt[1000005],target[1000005],tot;
void add(int x,int y){
    tot++;
    nxt[tot]=head[x];
    head[x]=tot;
    target[tot]=y;
}
void dfs(int x){
    if(flag) return;
    vis1[x]=vis2[x]=1;
    s.push(x);
    for(int i=head[x];i;i=nxt[i]){
        int y=target[i];
        if(vis2[y]){
            vector<int> v;
            while(s.top()!=y){
                v.push_back(s.top());
                s.pop();
            }
            v.push_back(y);
            cout<<v.size()<<'\n';
            for(int i=0;i<v.size();i++){
                cout<<v[i]<<' ';
            }
            cout<<'\n';
            flag=true;
            break;
        }
        if(vis1[y]) continue;
        dfs(y);
        if(flag) break;
    }
    vis2[x]=0;
    if(s.size()) s.pop();
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>t;
    while(t--){
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>a[i];
            add(i,i-a[i]);
        }
        dfs(1);
        flag=false;
        for(int i=1;i<=n;i++){
            vis1[i]=vis2[i]=0;
        }
        while(s.size()) s.pop();
    }
    return 0;
}
posted @ 2025-04-13 22:10  _Kenma  阅读(10)  评论(0)    收藏  举报