codeforces Round 1070(Div. 2)

D https://codeforces.com/contest/2176/problem/D

哎哎,经典的赛后过题。分享D的另一种不同的思路。
Hint1 首先可以观察到除了单独一条边成斐波那契数列的情况,其它更长的数列情况中,除了作为开头的两个点,其它的点都是严格单调递增的。
根据这个这个观察我们可以把图上原来{u,v}(ta[u]<ta[v])的边删除。这样就变成有向无环图了。
再运用dfs回溯+dp(可以参考代码理解),最后再加上单独一条边成斐波那契数列的情况就可以了。

附上代码

int n,m;cin>>n>>m;
int ans=m;
vvi g(n+1),g1(n+1);
vi din(n+1);
vi ta(n+1);
for (int i=1;i<=n;i++) cin>>ta[i];
for (int i=1;i<=m;i++)
{
    int u,v;cin>>u>>v;
    g[u].push_back(v);
}
for (int i=1;i<=n;i++)
{
    vi tc;
    for (auto v:g[i])
    {
        if(ta[v]>ta[i])
        {
            tc.push_back(v);
        }
        
    }
    g1[i]=g[i];
    g[i]=tc;
}
for (int i=1;i<=n;i++)
{
    auto tv=g[i];
    for (auto v:tv)
    {
        din[v]++;
    }
}
vi dp(n+1);
vi vis(n+1);
vector<map<int,int>> cnt(n+1);
auto dfs=[&](auto self,int u)->void
{
    vis[u]=1;
    // cout<<u<<endl;
    for (auto v:g[u])
    {
        din[v]--;
        if(vis[v]==0)
        self(self,v);
        cnt[u][ta[v]-ta[u]]=(cnt[u][ta[v]-ta[u]]+cnt[v][ta[u]]+1)%mod;
    }
};
for (int i=1;i<=n;i++)
{
    if(!din[i]&&vis[i]==0)
    {
        // cout<<i<<endl;
        dfs(dfs,i);
    }
}
for (int i=1;i<=n;i++)
{
    for (auto v:g1[i])
    {
        ans=(ans+cnt[v][ta[i]])%mod;
    }
    // cout<<i<<" "<<ans<<endl;
}
cout<<ans<<endl;
posted @ 2025-12-12 16:05  ddmdd  阅读(32)  评论(0)    收藏  举报