P8269 [USACO22OPEN] Visits S

题目描述

Bessie 的 NNN2≤N≤1052\le N\le 10^52N105)个奶牛伙伴(编号为 1⋯N1\cdots N1N)每一个都拥有自己的农场。对于每个 1≤i≤N1\le i\le N1iN,伙伴 i 想要访问伙伴 aia_iaiai≠ia_i\neq iai=i)。

给定 1…N1\ldots N1N 的一个排列 (p1,p2,…,pN)(p_1,p_2,\ldots, p_N)(p1,p2,,pN),访问按以下方式发生。

对于 111NNN 的每一个 iii

  • 如果伙伴 apia_{p_i}api 已经离开了她的农场,则伙伴 pip_ipi 仍然留在她的农场。
  • 否则,伙伴 pip_ipi 离开她的农场去访问伙伴 apia_{p_i}api 的农场。这次访问会产生快乐的哞叫 vpiv_{p_i}vpi 次(0≤vpi≤1090\le v_{p_i}\le 10^90vpi109)。

对于所有可能的排列 ppp,计算所有访问结束后可能得到的最大哞叫次数。

输入格式

输入的第一行包含 NNN

对于每一个 1≤i≤N1\le i\le N1iN,第 i+1i+1i+1 行包含两个空格分隔的整数 aia_iaiviv_ivi

输出格式

输出一个整数,为所求的答案。

注意这个问题涉及到的整数可能需要使用 64 位整数型(例如,C/C++ 中的 “long long”)。

输入输出样例 #1

输入 #1

4
2 10
3 20
4 30
1 40

输出 #1

90

说明/提示

【样例解释】

如果 p=(1,4,3,2)p=(1,4,3,2)p=(1,4,3,2),则

  • 伙伴 111 访问伙伴 222 的农场,产生 101010 次哞叫。
  • 伙伴 444 看到伙伴 111 已经离开了农场,所以无事发生。
  • 伙伴 333 访问伙伴 444 的农场,又产生 303030 次哞叫。
  • 伙伴 222 看到伙伴 333 已经离开了农场,所以无事发生。

这样总计得到了 10+30=4010+30=4010+30=40 次哞叫。

另一方面,如果 p=(2,3,4,1)p=(2,3,4,1)p=(2,3,4,1),则

  • 伙伴 222 访问伙伴 333 的农场,产生 202020 次哞叫。
  • 伙伴 333 访问伙伴 444 的农场,产生 303030 次哞叫。
  • 伙伴 444 访问伙伴 111 的农场,产生 404040 次哞叫。
  • 伙伴 111 看到伙伴 222 已经离开了农场,所以无事发生。

这样总计得到了 20+30+40=9020+30+40=9020+30+40=90 次哞叫。可以证明这是所有可能的排列 ppp 中访问结束后得到的最大可能的哞叫次数。

C++实现

#include<bits/stdc++.h>
using namespace std;
#define inf 1e18+10
#define int long long
const int maxn=100010;
int n,a[maxn],v[maxn],rd[maxn],ans,minn=inf;
bool vis[maxn];
queue<int>q;
void topo(){
    for(int i=1;i<=n;i++){
        if(!rd[i])q.push(i);
    }
    while(!q.empty()){
        int x=q.front();q.pop();
        ans+=v[x];rd[a[x]]--;
        vis[x]=1;
        if(!rd[a[x]])q.push(a[x]);
    }
    return;
}
void dfs(int x){
    vis[x]=1;
    minn=min(minn,v[x]);
    if(vis[a[x]])return;
    dfs(a[x]);
    return;
}
signed main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%lld%lld",&a[i],&v[i]);
        rd[a[i]]++;
    }
    topo();
    for(int i=1;i<=n;i++){
        if(!vis[i])ans+=v[i];
    }
    for(int i=1;i<=n;i++){
        if(vis[i])continue;
        minn=inf;dfs(i);
        ans-=minn;
    }
    printf("%lld",ans);
    return 0;
}

在这里插入图片描述

后续

接下来我会不断用C++来实现信奥比赛中的算法题、GESP考级编程题实现、白名单赛事考题实现,记录日常的编程生活、比赛心得,感兴趣的请关注,我后续将继续分享相关内容

更多推荐