DTOJ 1338

1 篇文章 0 订阅

题目描述

 

       话说世界上有很多超级英雄:蝙蝠侠,蜘蛛侠,超人,名字都写不出来的人

等等。在他们之中有一个叫Kickass。今天他想模仿蜘蛛侠,所以他选择了一排

高楼来跳。

            具体来说,他选择了一列N 幢高楼,从左到右标号为1 到N。一开始他在

第K 幢高楼。不幸的是,Kickass 能力非常有限,只能跳到向左或向右相邻的高

楼,而且他要跳到的楼的高度必须不能大于他现在处在的楼的高度。Kickass 不

想自己看起来很渣渣,所以他在一些高楼顶部放了蹦床,从这些高楼起跳,能跳

到任何其他的高楼,不管要跳到的高楼在哪里或是多高。

        你的任务是找到Kickass 在第K 高楼起跳能跳到的最多不同的高楼数。如果

Kickass 跳到一幢高楼超过一次,我们只会算一次。并且,即使Kickass 没有重新

跳到,第K 幢高楼还是要算入答案。

 

输入

 

第一行输入两个数:高楼数N(3<=N<=300,000),起跳位置K(1<=K<=N)。

第二行包括N 个小于10^6 的整数,表示1 到N 高楼的高度。

第三行包括一行N 个字符’.’或’T’。如果第i 个字符为’T’,则第i 幢楼上有蹦床。

spider.in 

10 1

10 7 3 1 1 9 8 2 4 10

..T..T....

 

输出

 

输出一行,最多可以跳到的楼数。

spider.out

7

 

样例输入

6 4
12 16 16 16 14 14
.T....

样例输出

5

提示

 

【样例解释】

第二个样例Kickass 经过高楼的顺序:

1 -> 2 -> 3 -> 6 -> 10 -> 9 -> 8

题解:

好题。

大概就是注意下相邻高楼之间的关系,以及从弹簧处出发可以到所有高楼。

我们肯定不可能将弹簧直接和其他点直接搞上联系,所以我们考虑建一个虚点,表示弹簧可以经过这个点,跳到所有的点上。

然后,我们再考虑将虚点与每个点搞上联系。

对于这种模型,可以考虑直接tarjan缩点然后在TAG上跑最长路。

好吧,这种模型我写的还不够多,一下子没反应过来。

 

 

#include<bits/stdc++.h>
using namespace std;
#define in inline
#define re register
#define rep(i,a,b) for(re int i=a;i<=b;i++)
#define repd(i,a,b) for(re int i=a;i>=b;i++)
#define For(i,a,b) for(re int i=a;i<b;i++)
#define _(d) while(d(isdigit(ch=getchar())))
template<class T>in void g(T&t){T x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch-48;_()x=x*10+ch-48;t=f*x;}
const int N=3e5+233; 
struct E{int to,nxt;}e[N*3];
vector<int>ee[N];
int head[N],tot,f[N],a[N],n,k,sz[N];char s[N];
in void ins(int x,int y){e[++tot]=E{y,head[x]};head[x]=tot;}
int dfn[N],low[N],c[N],cl,cnt,st[N],tp;
in void tarjan(int x){
	dfn[x]=low[x]=++cl;st[++tp]=x;
	for(int i=head[x];i;i=e[i].nxt){
		if(!dfn[e[i].to]){
			tarjan(e[i].to);
			low[x]=min(low[x],low[e[i].to]);
		}else if(!c[e[i].to])low[x]=min(low[x],dfn[e[i].to]);
	}
	if(low[x]==dfn[x]){
		++cnt;
		while(1)
		{int u=st[tp--];c[u]=cnt;sz[cnt]++;if(u==x) break;}
	}
}
in int dfs(int x){
	if(f[x]!=-1) return f[x];
	f[x]=0;
	For(i,0,ee[x].size()){
		int V=ee[x][i];
		f[x]=max(f[x],dfs(V));
	}f[x]+=sz[x];return f[x];
}
int main(){
	g(n),g(k);
	rep(i,1,n) g(a[i]);
	scanf("%s",s+1);
	rep(i,1,n){
		ins(n+1,i);
		if(s[i]=='T') ins(i,n+1);
		else{
			if(i<n&&a[i]>=a[i+1]) ins(i,i+1);
			if(i>1&&a[i]>=a[i-1]) ins(i,i-1);
		}
	}++n;memset(f,-1,sizeof(f));
	rep(i,1,n) if(!dfn[i]) tarjan(i);sz[c[n]]--;
	rep(x,1,n)
		for(int i=head[x];i;i=e[i].nxt)
			if(c[x]!=c[e[i].to]) ee[c[x]].push_back(c[e[i].to]);
	return !printf("%d\n",dfs(c[k]));
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

可爱の小公举

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值