Codeforces Round #660 (Div. 2) D. Captain Flint and Treasure ###K ### //K

题目链接:https://codeforces.ml/contest/1388/problem/D

题意:一种操作为 选一个下标 使得ans+=a[i] 且 把a[i]+到a[b[i]]中   要求每个下标都进行一种这样的操作,问怎么样的操作顺序才能使得ans最大

思路:要使得ans最大,那么肯定是a[i]为正数的都尽量早的累加,为负数的都尽量晚的累加,那么现在只需要考虑如何遍历就行了,题目已经说明是

有向无环图,那么首先想到的就应该是拓扑排序, 拓扑排序后, 正数应该从序号小的累加到序号大的, 这样能最大贡献, 负数应该从序号大的累加到序号小的,才能使得负数贡献小

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define pb push_back
 5 const int maxn =2e5+10;
 6 const int mod=1e9+7;
 7 ll a[maxn];
 8 int b[maxn];
 9 int ru[maxn];
10 int num[maxn];
11 
12 
13 bool cmp(pair<int,int>a,pair<int,int>b)
14 {
15     return a.first>b.first;
16 }
17 
18 int main()
19 {
20     ios::sync_with_stdio(false);
21     cin.tie(0);
22     int n;
23     cin>>n;
24     for(int i=1;i<=n;i++)
25     {
26         cin>>a[i];
27     }
28     for(int i=1;i<=n;i++)
29     {
30         cin>>b[i];
31         if(b[i]==-1)
32             b[i]=0;
33         ru[b[i]]++;
34     }
35     queue<int>q;
36     for(int i=1;i<=n;i++)
37     {
38         if(ru[i]==0)
39             q.push(i);
40     }
41     ll ans=0;
42     vector<int>cnt;
43     int tot=0;
44     while(!q.empty())
45     {
46         int u=q.front();
47         num[u]=++tot;
48         int v=b[u];
49         q.pop();
50         if(a[u]>=0)
51         {
52             a[v]+=a[u];
53             ans+=a[u];
54             cnt.pb(u);
55         }
56         ru[v]--;
57         if(ru[v]==0&&v!=0)
58             q.push(v);
59     }
60     vector<pair<int,int>>temp;
61     for(int i=1;i<=n;i++)
62     {
63         if(a[i]<0)
64         {
65             temp.pb({num[i],i});
66         }
67     }
68     sort(temp.begin(),temp.end(),cmp);
69     for(auto &v:temp)
70     {
71         ans+=a[v.second];
72         cnt.pb(v.second);
73     }
74 
75     cout<<ans<<'\n';
76     for(auto &v:cnt)
77         cout<<v<<" ";
78 
79 
80 
81 
82 
83 }
View Code
posted @ 2020-08-02 19:45  canwinfor  阅读(217)  评论(0)    收藏  举报