Codeforces Beta Round #5 解题报告

上古比赛题目有点毒啊。。

CBR 5

A. Chat Server's Outgoing Traffic

题意:一个通讯工具,支持加人删人,计算最终流量  流量=sigma(每条信息长度*在线人数和)



暴力即可。

因为信息中间有空格,所以需要用getline

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
#include<ctime>
#include<algorithm>
#define For(i,j,k)  for(register ll i=j;i<=k;++i)
#define Dow(i,j,k)  for(register ll i=k;i>=j;--i)
#define ll long long
#define mk make_pair
#define pb push_back
#define eps 1e-8
#define pa pair<ll,ll>
#define fir first
#define sec second
using namespace std;
inline ll read()
{
    ll t=0,f=1;char c=getchar();
    while(c<'0'||c>'9')   {if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') t=t*10+c-48,c=getchar();
    return t*f;
}
int now,ans;
char s[200001];
int main()
{
	now=0;
	while(cin.getline(s,10001))
	{
		if(s[0]=='+')now++;else
		if(s[0]=='-')now--;else
		{
			int len=strlen(s);
			For(i,0,len)	if(s[i]==':')	ans+=(len-1-i)*now;
		}
	}
	cout<<ans<<endl;
}


B. Center Alignment

题意:把每个串居中排列,如果左右空格不能均等, 第一次往左靠,第二次往右靠……

题意有毒……看错两次mmp

乱搞即可,还是getline

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
#include<ctime>
#include<algorithm>
#define For(i,j,k)  for(register ll i=j;i<=k;++i)
#define Dow(i,j,k)  for(register ll i=k;i>=j;--i)
#define ll long long
#define mk make_pair
#define pb push_back
#define eps 1e-8
#define pa pair<ll,ll>
#define fir first
#define sec second
using namespace std;
inline ll read()
{
    ll t=0,f=1;char c=getchar();
    while(c<'0'||c>'9')   {if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') t=t*10+c-48,c=getchar();
    return t*f;
}
int n,mx,lres,rres;
int lef=1;
char s[10001][1100];
int main()
{
	n=1;
	while(cin.getline(s[n],1000))	n++;
	n--;
	For(i,1,n)	mx=max(mx,(int)strlen(s[i]));
	For(i,1,mx+2)	putchar('*');puts("");
	For(i,1,n)
	{
		int len=strlen(s[i]);
		lres=(mx-len)/2;rres=mx-len-lres;
		if(lres!=rres)	if(!lef)	swap(lres,rres),lef=1;else lef=0;
		putchar('*');For(j,1,lres)	putchar(' ');
		For(j,0,len-1)	putchar(s[i][j]);
		For(j,1,rres)	putchar(' ');
		puts("*");
	}	
	For(i,1,mx+2)	putchar('*');puts("");
}


C. Longest Regular Bracket Sequence

题意:给你一个括号序列,问最长的合法括号序列以及数量

我一开始写的直接记录左括号减右括号……发现这个东西并不能统计合法序列长度= =

然后瞎yy了一个算法

用栈模拟维护出可以成功匹配的位置,vis[i]=1表示i号节点可以匹配

按照合法括号序列的定义,我们不难发现,这个问题变成了连续1的最大长度以及数量

遍历一下vis数组即可

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
#include<ctime>
#include<algorithm>
#define For(i,j,k)  for(register ll i=j;i<=k;++i)
#define Dow(i,j,k)  for(register ll i=k;i>=j;--i)
#define ll long long
#define mk make_pair
#define pb push_back
#define eps 1e-8
#define pa pair<ll,ll>
#define fir first
#define sec second
using namespace std;
inline ll read()
{
    ll t=0,f=1;char c=getchar();
    while(c<'0'||c>'9')   {if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') t=t*10+c-48,c=getchar();
    return t*f;
}
char s[2000001];
int n,len,now,mx,tot,q[2000001],top;
bool vis[2000001];
int main()
{
	scanf("\n%s",s+1);
	n=strlen(s+1);
	bool lx=0;
	For(i,1,n)
		if(s[i]=='(')	q[++top]=i;
		else	
			if(top>0)	vis[q[top]]=1,vis[i]=1,top--;
	For(i,1,n)	
		if(vis[i])	len++;else	
		{
			if(len>mx)	mx=len,tot=1;else	if(len==mx)	tot++;
			len=0;
		}
	if(len>mx)	mx=len,tot=1;else	if(len==mx)	tot++;
	if(mx==0)	puts("0 1");else 
	cout<<mx<<' '<<tot<<endl;
}

D. Follow Traffic Rules

…………不知道是我太弱了还是这题太毒瘤了,卡了我一个小时

题意:一辆小车加速度为a,最大速度为v,要通过一段长度为l的路,在距离起点d的位置有一个限速牌,即你通过这个点时的速度不能大于w,问通过这段路的最短时间


大力分类讨论…………

通过d点之前,三类:

1、一直加速

2、先加速再匀速再减速

3、先加速再减速


这里1、2两类都是比较容易讨论出时间的,第三类需要列一个方程解一下,时间是sqrt((2*d+w^2/a)/2a))

接下来发现2、3两类过d点后的速度均为w,第一类为at

显然在这之后分两类

1、一直加速

2、先加速后匀速

这样就可以了……反正各种解方程啊求临界啊真是mmmmp了

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
#include<ctime>
#include<algorithm>
#define For(i,j,k)  for(register ll i=j;i<=k;++i)
#define Dow(i,j,k)  for(register ll i=k;i>=j;--i)
#define ll long long
#define mk make_pair
#define pb push_back
#define eps 1e-8
#define pa pair<ll,ll>
#define fir first
#define sec second
using namespace std;
inline ll read()
{
    ll t=0,f=1;char c=getchar();
    while(c<'0'||c>'9')   {if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') t=t*10+c-48,c=getchar();
    return t*f;
}
double a,v,l,d,w,ans;
inline void spe(double v1)
{
	double res=l-d;
	w=v1;
	double t2=(v-w)/a;
	if(t2*(v+w)/2<=res)
	{
		res-=t2*(v+w)/2;
		ans+=t2+res/v;
	}else
	{
		ans+=(-2*w+sqrt(4*w*w+8*res*a))/(2*a);	
	}	
	printf("%.9lf",ans);
}
int main()
{
	a=read();v=read();
	l=read();d=read();w=read();
	if(w>v)
	{
		double dis=0;	
		double ans=0;
		dis=v*v/(2*a);
		double t=sqrt(2*l/a);
		if(t*a>v)	ans=(v/a)+(l-dis)/v;
		else	
			ans=sqrt(2*l/a);
		printf("%.9lf\n",ans);
		return 0;
	}
	ans=0;
	double t=sqrt(2*d/a);
	if(t*a<=w)	ans+=t,spe(t*a);
	else
	{
		double t2=sqrt((2*d+w*w/a)/(2*a));
		if(t2*a<=v)
		{
			ans+=t2+(t2-w/a);
		}else
		{
			double x=0;
			double t1=0,t3=0;
			t1=v/a;x+=(v/2*t1);
			t3=(v-w)/a;x+=(v+w)/2*t3;
			ans+=(d-x)/v+t1+t3;
		}	
		double res=l-d;
		t2=(v-w)/a;
		if(t2*(v+w)/2<=res)
		{
			res-=t2*(v+w)/2;
			ans+=t2+res/v;
		}else
		{
			ans+=(-2*w+sqrt(4*w*w+8*res*a))/(2*a);	
		}	
		printf("%.9lf",ans);
	}	
}

E. Bindian Signalizing

get新姿势

题意:一个环上,有n座山,两座山之间能看见当且仅当顺时针或者逆时针方向上没有大于他们的山


这种题第一反应就是拆环之后单调栈

但是发现相等的情况很难处理= =

于是搜了一波题解

大概思路是这样的

在一般情况(所有点都不相同)下,一个点可以从顺时针找到第一个比他大的和逆时针第一个比他大的,是这座山顺时针/逆时针唯一可以看到的山。(大于的情况下,小于的情况在做较小的山时会被算到)

但是有一种情况,就是他的逆时针和顺时针找到的同一座山,只有可能是最高的山

所以我们以最高的山为首尾拆环,然后求一下lnxt[i]和rnxt[i]分别表示左右第一个比他大的,在计算rnxt[i]或lnxt[i]的同时,可以求出可以相互看到的相等高度的山的数量,计算答案即可

”所以我们以最高的山为首尾拆环”

感觉这个思路非常的妙啊!

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
#include<ctime>
#include<algorithm>
#define For(i,j,k)  for(register ll i=j;i<=k;++i)
#define Dow(i,j,k)  for(register ll i=k;i>=j;--i)
#define ll long long
#define mk make_pair
#define pb push_back
#define eps 1e-8
#define pa pair<ll,ll>
#define fir first
#define sec second
using namespace std;
inline ll read()
{
    ll t=0,f=1;char c=getchar();
    while(c<'0'||c>'9')   {if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') t=t*10+c-48,c=getchar();
    return t*f;
}
ll n,a[2000001],b[2000001],top,mx,ans,rnxt[2000001],lnxt[2000001],tot[2000001];
int main()
{
	n=read();
	For(i,1,n)	a[i]=read();
	For(i,1,n)	mx=max(mx,a[i]);
	For(i,1,n)	
	if(a[i]==mx)
	{
		For(j,i,n)	b[++top]=a[j];
		For(j,1,i)	b[++top]=a[j];
		break;
	}
	For(i,1,top)	a[i]=b[i];
	Dow(i,1,n)
	{
		rnxt[i]=i+1;
		while(rnxt[i]!=n+1&&a[rnxt[i]]<a[i])	rnxt[i]=rnxt[rnxt[i]];
		while(rnxt[i]!=n+1&&a[rnxt[i]]==a[i])	tot[i]=tot[rnxt[i]]+1,rnxt[i]=rnxt[rnxt[i]];//右边第一个严格大于i  以及之间有多少额外(相等)对 
	}
	For(i,2,n)
	{
		lnxt[i]=i-1;
		while(lnxt[i]!=1&&a[lnxt[i]]<a[i])	lnxt[i]=lnxt[lnxt[i]];
		while(lnxt[i]!=1&&a[lnxt[i]]==a[i])	lnxt[i]=lnxt[lnxt[i]];
		ans+=tot[i];
		ans+=2;
		if(lnxt[i]==1&&rnxt[i]==n+1)	ans--;
	}
	cout<<ans<<endl;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值