AtCoder Beginner Contest 366

A

题目大意:给你总的比赛场次数,再给你目前的比分,问你这场比赛的结果是不是已经出来了。

也就是有一个人的分数达到n/2+1就代表结束了

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m,t,a[N];
int main()
{
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
//	cout<<fixed<<setprecision(2);
	cin>>n>>t>>m;
	if(t>=(n+1)/2||m>=(n+1)/2)cout<<"Yes"<<endl;
	else cout<<"No"<<endl;
}

B

题目大意:给你n个字符串,让你按列的顺序逆序输出,在同一列长度下部分字符串是没有的,就用星号*来表示,并且删除后缀的星号。

模拟。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m,t;
string a[N];
int main()
{
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
//	cout<<fixed<<setprecision(2);
	cin>>n;
	int M=0;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		if(M<a[i].size())M=a[i].size();
	}
	string ans[N];
	for(int i=0;i<M;i++)
	{
		for(int j=n;j>=1;j--)
		{
			if(i<a[j].size())ans[i]+=a[j][i];
			else ans[i]+='*';
		}
	}
	for(int i=0;i<M;i++)
	{
		while(ans[i].size()&&ans[i][ans[i].size()-1]=='*')ans[i].erase(ans[i].size()-1);
	}
	for(int i=0;i<M;i++)cout<<ans[i]<<endl;
}

C

题目大意:1 x代表加入x这个数,2 x代表删除这个数,3即输出现在还有多少种数字。

一个set用来标记数字的种数,map用来记录数字的数量,输出就输出set的size。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m,t;
map<int,int>p;
set<int>q;
int main()
{
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
//	cout<<fixed<<setprecision(2);
	cin>>t;
	while(t--)
	{
		int x,y;
		cin>>x;
		if(x==1)
		{
			cin>>y;
			p[y]++;
			if(p[y]==1)
			{
				q.insert(y);
			}
		}
		else if(x==2)
		{
			cin>>y;
			p[y]--;
			if(p[y]==0)
			{
				q.erase(q.find(y));
			}
		}
		else if(x==3)
		{
			cout<<q.size()<<endl;
		}
	}
}

D

题目大意:三维前缀和。

也就是三维前缀和。

a[i][j][p]+=a[i-1][j][p]+a[i][j-1][p]+a[i][j][p-1]-a[i-1][j-1][p]-a[i-1][j][p-1]-a[i][j-1][p-1]+a[i-1][j-1][p-1];

以及查询

ans=a[rx][ry][rz]-a[lx-1][ry][rz]-a[rx][ly-1][rz]-a[rx][ry][lz-1]+a[lx-1][ly-1][rz]+a[lx-1][ry][lz-1]+a[rx][ly-1][lz-1]-a[lx-1][ly-1][lz-1];

#include<bits/stdc++.h>
using namespace std;
const int N=1e2+10;
int n,m,t,a[N][N][N],q;
int main()
{
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
//	cout<<fixed<<setprecision(2);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			for(int p=1;p<=n;p++)cin>>a[i][j][p];
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			for(int p=1;p<=n;p++)
			{
				a[i][j][p]+=a[i-1][j][p]+a[i][j-1][p]+a[i][j][p-1]-a[i-1][j-1][p]-a[i-1][j][p-1]-a[i][j-1][p-1]+a[i-1][j-1][p-1];
			}
		}
	}
	cin>>q;
	while(q--)
	{
		int lx,rx,ly,ry,lz,rz;
		cin>>lx>>rx>>ly>>ry>>lz>>rz;
		int ans=a[rx][ry][rz]-a[lx-1][ry][rz]-a[rx][ly-1][rz]-a[rx][ry][lz-1];
		ans=ans+a[lx-1][ly-1][rz]+a[lx-1][ry][lz-1]+a[rx][ly-1][lz-1]-a[lx-1][ly-1][lz-1];
		cout<<ans<<endl;
	}
}

E

题目大意:给你n个二维点,还有一个D,要求有一个点与这n个点的曼哈顿距离必须小于等于D。问一共有多少个这样的点。

优先降维,将二维分成x和y这两个一维,那么在x轴符合条件的x坐标,找到对应有多少y轴坐标数量符合条件,那么就是总的可能性。

可以发现,在x这个点上时,他的差值和为sum。那么在x+1这个点上时,左边的点数量是l,右边的点数量是r,那么x+1上的差值和就是sum-l+r。

如果放在函数上就是一个单峰函数,也可能是个平底锅。这同样适用于y坐标,所以我们只要枚举所有的x坐标,然后找到可行的y坐标范围就可以了。

内存分配了一个g,那就瞎预处理,内存反正够用,把每个y坐标的曼哈顿距离全部处理出来,并以峰值点为中心点进行分割,分成两部分,排个序让这两部分都是递增序列,这样我们查找的时候直接upper_bound查可能得y值就可以直接查到数量了。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=6e6+10;
int n,m,t,x[N],y[N],a[N],b[N],sumx,sumy,d,ans,Miny;
vector<int>ly,ry;
void Init()
{
	int t=1;
	for(int i=0;i<=6e6;i++)
	{
		while(t<=n&&x[t]<i)t++;
		if(i!=0)
		{
			sumx+=t-1;
			sumx-=n-t+1;
		}
		a[i]=sumx;
	}
	t=1;
	for(int i=0;i<=6e6;i++)
	{
		while(t<=n&&y[t]<i)t++;
		if(i!=0)
		{
			sumy+=t-1;
			sumy-=n-t+1;
		}
		b[i]=sumy;
		if(b[Miny]>sumy)Miny=i;
	}
	for(int i=0;i<=Miny;i++)ly.push_back(b[i]);
	for(int i=Miny+1;i<=6e6;i++)ry.push_back(b[i]);
	sort(ly.begin(),ly.end());
	sort(ry.begin(),ry.end());
}
int sanfen(int x)
{
	if(d-a[x]<0)return 0;
	int p=d-a[x];
	int l=0;
	int r=0;
	if(upper_bound(ly.begin(),ly.end(),p)!=ly.end())
	{
		l=upper_bound(ly.begin(),ly.end(),p)-ly.begin();
	}
	if(upper_bound(ry.begin(),ry.end(),p)!=ry.end())
	{
		r=upper_bound(ry.begin(),ry.end(),p)-ry.begin();
	}
//	cout<<l+r<<" "<<p<<endl;
	return r+l;
}
signed main()
{
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
//	cout<<fixed<<setprecision(2);
	cin>>n>>d;
	for(int i=1;i<=n;i++)cin>>x[i]>>y[i],x[i]+=3e6,y[i]+=3e6,sumx+=x[i],sumy+=y[i];
	sort(x+1,x+1+n);
	sort(y+1,y+1+n);
	Init();
//	cout<<a[2000000]<<" "<<b[2000000]<<endl;
	for(int i=0;i<=6e6;i++)
	{
		ans+=sanfen(i);
	}
	cout<<ans<<endl;
}

因为有负坐标,所以我们就把所有坐标加3e6,那么题目的坐标就会在2e6到3e6之间,可行的x坐标就在1e6到4e6之间。但是这么区划范围交上去会wa四个,所以我就扩到0到6e6之间了。赛时做出来wa了我还以为方法错了,结果赛后查别人代码的时候发现怎么8e6都开出来了,我就回去改了一下就过了,绝望了直接。

上一场E题思路直接想歪了,还以为线段树优化呢,结果是异或前缀和的性质,就不想写了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值