码迷,mamicode.com
首页 > 其他好文 > 详细

codeforces 894E

时间:2020-02-11 11:31:29      阅读:49      评论:0      收藏:0      [点我收藏+]

标签:可以转化   部分   turn   pop   lap   spl   缩点   efi   sum   

显然如果走到一个SCC里,那么可以把这个SCC里的权值反复走取完

连接SCC之间的边显然只能走一次(缩点后是DAG)

那么我们tarjan缩点,然后在DAG上DP,就是个带权最长路,随便DP一下就行了

边权就是w,点权需要另外计算

对每个SCC内部的边,假设边权为\(w\),那么下降次数是满足\(\frac{(t+1)*t}{2} \leq w\)的最大的\(t\),这个可以二分出来

然后考虑贡献了多少,用整体减掉下降的每种权值的贡献,实际上是\((t+1)*w-t*1-(t-1)*2-…-2*(t-1)-1*t\)

后面那部分写成和式的形式是\(\sum_{i=1}^{t}{i*(t+1-i)}\)

然后这个拆开来可以转化成等差数列和加平方和计算

技术图片
 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define maxn 1000005
 4 using namespace std;
 5 int n,m,s;
 6 vector< pair<int,int> > g[maxn],g2[maxn];
 7 stack<int> stk;
 8 vector<int> scc[maxn];
 9 int pre[maxn],low[maxn],bel[maxn],Tim,cnt;
10 void tarjan(int u)
11 {
12     pre[u]=low[u]=++Tim;
13     stk.push(u);
14     for(auto pa:g[u])
15     {
16         int v=pa.first;
17         if(!pre[v])tarjan(v),low[u]=min(low[u],low[v]);
18         else if(!bel[v])low[u]=min(low[u],pre[v]);
19     }
20     if(low[u]==pre[u])
21     {
22         cnt++;
23         while(1)
24         {
25             int x=stk.top();stk.pop();
26             bel[x]=cnt;
27             scc[cnt].push_back(x);
28             if(x==u)break;
29         } 
30     }
31 }
32 ll calc(ll w)
33 {
34     ll l=0,r=20000,t=0;
35     while(l<=r)
36     {
37         ll mid=(l+r)>>1;
38         if(mid*(mid+1)<=2*w)t=mid,l=mid+1;
39         else r=mid-1;
40     }
41     return (t+1)*w-((t+1)*(t+1)*t/2-t*(t+1)*(2*t+1)/6);
42 }
43 ll we[maxn],dp[maxn];
44 void dfs(int u)
45 {
46     if(dp[u])return;
47     dp[u]=0;
48     for(auto pa:g2[u])
49     {
50         int v=pa.first,w=pa.second;
51         dfs(v);
52         dp[u]=max(dp[u],dp[v]+w);
53     }
54     dp[u]+=we[u];
55 }
56 int main()
57 {
58     scanf("%d%d",&n,&m);
59     for(int u,v,w,i=1;i<=m;++i)
60     {
61         scanf("%d%d%d",&u,&v,&w);
62         g[u].push_back(make_pair(v,w));
63     }
64     Tim=cnt=0;
65     for(int i=1;i<=n;++i)if(!pre[i])tarjan(i);
66     for(int u=1;u<=n;++u)
67     {
68         for(auto pa:g[u])
69         {
70             int v=pa.first,w=pa.second;
71             if(bel[u]==bel[v])we[bel[u]]+=calc(w);
72             else g2[bel[u]].push_back(make_pair(bel[v],w));
73         }
74     }
75     scanf("%d",&s);
76     dfs(bel[s]);
77     printf("%lld\n",dp[bel[s]]);
78 }
View Code

 

codeforces 894E

标签:可以转化   部分   turn   pop   lap   spl   缩点   efi   sum   

原文地址:https://www.cnblogs.com/uuzlove/p/12294133.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!