Jzoj3176 蜘蛛侠
话说世界上有很多超级英雄:蝙蝠侠,蜘蛛侠,超人,名字都写不出来的人等等。在他们之中有一个叫Kickass。今天他想模仿蜘蛛侠,所以他选择了一排高楼来跳。
具体来说,他选择了一列N幢高楼,从左到右标号为1到N。一开始他在第K幢高楼。不幸的是,Kickass能力非常有限,只能跳到向左或向右相邻的高楼,而且他要跳到的楼的高度必须不能大于他现在处在的楼的高度。Kickass不想自己看起来很渣渣,所以他在一些高楼顶部放了蹦床,从这些高楼起跳,能跳到任何其他的高楼,不管要跳到的高楼在哪里或是多高。
你的任务是找到Kickass在第K高楼起跳能跳到的最多不同的高楼数。如果Kickass跳到一幢高楼超过一次,我们只会算一次。并且,即使Kickass没有重新跳到,第K幢高楼还是要算入答案。
刷水题有利于身心健康
非常简单的图论题,tarjan缩点之后跑DAG最长路就好,代码基本不用变直接搬过来就能用
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<vector>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 300010
using namespace std;
struct Edge{ int v,nt; } G[N*3]; char s[N];
int h[N],dfn[N],low[N],col[N],f[N],n,m,cnt=0;
vector<int> G2[N]; int st[N],top=0,clk=0,Col,sz[N],v[N];
inline void adj(int x,int y){ G[++cnt]=(Edge){y,h[x]}; h[x]=cnt; }
void tarjan(int x){
dfn[x]=low[x]=++clk;
st[++top]=x;
for(int v,i=h[x];i;i=G[i].nt)
if(!dfn[v=G[i].v]){
tarjan(v); low[x]=min(low[x],low[v]);
} else if(!col[v]) low[x]=min(low[x],dfn[v]);
if(low[x]==dfn[x]){
++Col;
do { col[st[top]]=Col; sz[Col]++; } while(st[top--]!=x);
}
}
int dp(int x){
if(~f[x]) return f[x]; f[x]=0;
for(int i=0,z=G2[x].size();i<z;++i) f[x]=max(f[x],dp(G2[x][i]));
f[x]+=sz[x]; return f[x];
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d",v+i); scanf("%s",s+1);
for(int i=1;i<=n;++i){
adj(n+1,i);
if(s[i]=='T') adj(i,n+1);
else{
if(i>1&&v[i]>=v[i-1]) adj(i,i-1);
if(i<n&&v[i]>=v[i+1]) adj(i,i+1);
}
}
memset(f,-1,sizeof f); ++n;
for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i); sz[col[n]]--;
for(int i=1;i<=n;++i)
for(int j=h[i];j;j=G[j].nt)
if(col[i]!=col[G[j].v]) G2[col[i]].push_back(col[G[j].v]);
printf("%d\n",dp(col[m]));
}