Codeforce div2 578

A. Hotelier

建一个10个空间的数组,代表十个房间,0代表没人,1代表有人。

L就从左找第一个为0的房间,赋1;R就从右找第一个为0的房间,赋1;数字就把那个房间清空。

复杂度O(10N)最多1e6。

注意房间从0开始,写循环<=0后者>=0!

else只与最近的if匹配!!!!不想匹配记得加括号!!!

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
int r[15];
string s;
int main()
{
	int n;
	cin>>n;
	cin>>s;
	for(int j=0;j<n;j++)
	{
		if(s[j]=='L')
		{
			for(int i=0;i<10;i++)
				if(r[i]==0)
				{
					r[i]=1;
					break;
				}
		}
		else if(s[j]=='R')
		{
			for(int i=9;i>=0;i--)//这里是>=0不是>0!!!
				if(r[i]==0)
					{
						r[i]=1;
						break;
					}
		}
		else r[s[j]-'0']=0;
	}
	for(int i=0;i<10;i++)
		cout<<r[i];
}//else只与最近的if匹配 

B. Block Adventure

跳柱子问题,从上一个到下一个最多跳k高度,可以从柱子上拿砖或放砖。

把背包所有砖放在当前柱子,和下一个柱子做差,h[i+1]-(m+h[i])<k 代表可以翻过去;设每次翻越m会得到n块,h[i+1]-(h[i]-n)=k,无论n正负都是成立的,n为负时代表最少放柱子上n块,n为正时代表最多拿n块。n=k-h[i+1]+h[i],即每一次翻越后,m+=k-h[i+1]+h[i],但是一次最多拿h[i]块,每一次m+=min(h[i],k-h[i+1]+h[i])。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
int h[110];
int main()
{
	int t,n,m,k;
	
	cin>>t;
	while(t--)
	{
		bool flag=1;
		cin>>n>>m>>k;
		for(int i=1;i<=n;i++)
			cin>>h[i];
		for(int i=1;i<n;i++)
		{
			if(h[i+1]-h[i]-m>k)
			{
				flag=0;
				break;
			}
			else
			{
				if(k-h[i+1]+h[i]<h[i])
					m+=k-h[i+1]+h[i];
				else
					m+=h[i];
			}
		}
		if(flag)
			cout<<"YES"<<endl;
		else
		 	cout<<"NO"<<endl;
	}
}

C. Round Corridor

题意是里面一个内圆,一个外圆,内圆被等角度的n个均匀分布的墙分成n块,外圆被m个均匀分布的墙分成m块,问你从某一块能不能到另一块。

在某一角度,如果内圆于外圆在此角度都有墙,那这个角度将被锁死是不能通过的。这种死墙的个数就是n,m的公因数。看图就很容易看出来。死墙将圆分成gcd(n,m)块,起点和终点不在一个块就无法到达。判断:

外墙第i块在第

(i-1)/(m/g)

 内墙第j块就是

(j-1)/(n/g)

 注意是(i-1)

从0开始计数的分块不用-1,从1开始的都需要

记得开long long

一开始还以为一定是起点终点一个内一个外,审题!!!!!!!!!看完题看一下样例!!!!!

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long LL;
LL gcd(LL a,LL b)
{
	if(b==0)
		return a;
	if(b>a)
		return gcd(b,a) ;
	return gcd(b,a%b); 
}
int main()
{
	LL n,m,sy,ey;
	LL q,ex,sx;
	cin>>n>>m>>q;
	while(q--)
	{
		cin>>sx>>sy>>ex>>ey;
		LL g=gcd(n,m),a,b;//这里当时忘写longlong了,醉了
		if(sx==1)
			a=(sy-1)/(n/g);
		else
			a=(sy-1)/(m/g);
		if(ex==1)
			b=(ey-1)/(n/g);
		else
			b=(ey-1)/(m/g);
		if(a!=b)
			cout<<"NO"<<endl;
		else
			cout<<"YES"<<endl;
	}
}

 D. White Lines

一个n*n的正方形,有白色黑色两种色块,你能消除k*k正方形里的所有黑色,问一次操作后,全是白色的行和列之和的最大值。

分成行列两种情形分别计算。

想将一行的变成白色,就要将所有黑色覆盖掉,因为只能一片的进行覆盖,所以只需要考虑这行第一个黑块和最后一个黑块,只要它们俩被覆盖掉,那么这行就会变成全白,假设第一个位置是l,最后一个是r,先赋予初值-1。新建一个n*n方格,ans[i][j]表示当k*k左上角在(i,j)位置时,全白行和全白列的数量。不包括一开始就全白的。

以行的情况举例:

1、第i行没有黑块,r=l=-1,那么用anss来存储,anss++,意味着无论放哪里答案都有这一行

2、r-l+1<=k意味着这一行可以被覆盖,那么能覆盖的k*k方块左上角的格子ans[ii][jj]++;ii的范围是[i-k+1,i],设dis=r-l+1,jj的范围是[l+dis-k,l]。都是闭区间

 3.r-l+1>k那么放哪里这一行都不会全白,直接下一行。

列的情况相同。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
char sq[2010][2010];
int ans[2010][2010];
int main()
{
	int n,k,f=0,anss=0;
	cin>>n>>k;
	for(int i=0;i<n;i++)
		cin>>sq[i];
	for(int i=0;i<n;i++)
	{
		int l=-1,r=-1,f=0;
		for(int j=0;j<n;j++)
		{
			if(sq[i][j]=='B')
			if(l==-1)
				l=j,r=j;
			else 
			{
				r=j;
				if(r-l+1>k)
				{
					f=1;
					break;
				}
			}
		}
		if(l==-1) 
		{	
			anss++;
			continue;
		}
		if(f==1)
			continue;
		int dis=r-l+1;
		for(int ii=0;ii<=k-1;ii++)
		{
			if(i-ii<0) break;
			for(int jj=0;jj<=k-dis;jj++)
			{
				if(l-jj<0) break;
				ans[i-ii][l-jj]++;
			}
		}
	}
	for(int i=0;i<n;i++)
	{
		int l=-1,r=-1,f=0;
		for(int j=0;j<n;j++)
		{
			if(sq[j][i]=='B')
			if(l==-1)
				l=j,r=j;
			else 
			{
				r=j;
				if(r-l+1>k)
				{
					f=1;
					break;
				}
			}
		}
		if(l==-1) 
		{	
			anss++;
			continue;
		}
		if(f==1)
			continue;
		int dis=r-l+1;
		for(int ii=0;ii<=k-dis;ii++)
		{
			if(l-ii<0) break;
			for(int jj=0;jj<=k-1;jj++)
			{
				if(i-jj<0) break;
				ans[l-ii][i-jj]++;
			}
		}
	}
	int maxn=0;
	for(int i=0;i<n;i++)
		for(int j=0;j<n;j++)
			maxn=max(maxn,ans[i][j]);
	cout<<maxn+anss;
}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值