AtCoder Beginner Contest 269

比赛链接

A

模拟即可。

点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
int a,b,c,d;
signed main()
{
	cin>>a>>b>>c>>d;
	cout<<(a+b)*(c-d)<<endl;
	cout<<"Takahashi";
	return 0;
}

B

找到由 * 组成的正方形的四角。

把所有的 * 的横纵坐标取最大,最小即为答案。

点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
int a=114514,b,c=114514,d;
char ch[20][20];
signed main()
{
	for(int i=1;i<=10;++i)
		for(int j=1;j<=10;++j)
			cin>>ch[i][j];
	for(int i=1;i<=10;++i)
	{
		for(int j=1;j<=10;++j)
		{
			if(ch[i][j]=='#')
			{
				a=min(a,i);
				b=max(b,i);
				c=min(c,j);
				d=max(d,j);
			}
		}
	}
	cout<<a<<" "<<b<<endl<<c<<" "<<d;
	return 0;
}

C

裸的穷举子集。
for(int i=x;i;i=(i-1)&x)
输出答案可以用一个栈保证由小到大。

点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
int x;
stack<int>st;
signed main()
{
	cin>>x;
	for(int i=x;i;i=(i-1)&x)
		st.push(i);
	cout<<0<<endl;
	while(!st.empty())
	{
		cout<<st.top()<<endl;
		st.pop();
	}
	return 0;
}

D

求蜂窝图中的连通块的个数。

dfs 即可,注意打访问标记。
为了防止下标出现负数需要进行偏移。

点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=3006;
int n,mp[N][N],vis[N][N],rex[N],rey[N],ans=0;
int dx[6]={-1,-1,0,0,1,1};
int dy[6]={-1,0,-1,1,0,1};
void dfs(int x,int y,int col)
{
	if(!mp[x+1001][y+1001]||vis[x+1001][y+1001])return;
	mp[x+1001][y+1001]=col;vis[x+1001][y+1001]=1;
	for(int i=0;i<6;++i)dfs(x+dx[i],y+dy[i],col);
}
signed main()
{
	cin>>n;
	for(int i=1;i<=n;++i)
	{
		cin>>rex[i]>>rey[i];
		mp[rex[i]+1001][rey[i]+1001]=i;	
	}
	for(int i=1;i<=n;++i)	
		if(mp[rex[i]+1001][rey[i]+1001]==i)
			ans++,dfs(rex[i],rey[i],i);
	cout<<ans;
	return 0;
}

E

水交互。二分即可。
注意一些交互格式。

点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1005;
int n,x,y;
signed main()
{
	cin>>n;
	int l=1,r=n;
	while(l<r)
	{
		int mid=(l+r)>>1;
		cout<<"? "<<l<<" "<<mid<<" "<<1<<" "<<n<<endl;
		int t;cin>>t;
		if(t==mid-l+1)l=mid+1;
		else r=mid;
	}
	x=l;l=1,r=n;
	while(l<r)
	{
		int mid=(l+r)>>1;
		cout<<"? "<<1<<" "<<n<<" "<<l<<" "<<mid<<endl;
		int t;cin>>t;
		if(t==mid-l+1)l=mid+1;
		else r=mid;
	}
	y=l;
	cout<<"! "<<x<<" "<<y<<endl;
	return 0;
}

F

区间问题,不难想到用二维前缀和将问题转化为求 \((1,1)\)\((x,y)\) 区间的点权和。

考虑如何求出 \((1,1)\)\((x,y)\) 区间的点权和,发现每两列的和成等差数列(1,2列的和 和 3,4列的和 和 5,6列的和成等差数列)。通过一些高斯求和法的计算可以得出头两列的和,和最后两个成对的列的和,再次进行求和可以得出答案。但是要特判最后一列。

点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod=998244353;
int n,m,q,inv=mod/2+1;
int f(int x,int y) 
{
	int st1,st2,ed1,ed2;
	if(y%2==0)
	{
		st1=(1+y-1)*(y/2)%mod*inv%mod;
		st2=(m+2+m+y)*(y/2)%mod*inv%mod;
		ed1=(((x/2*2-2)*m+1)%mod+((x/2*2-2)*m+y-1)%mod)*(y/2)%mod*inv%mod;
		ed2=(((x/2*2-1)*m+2)%mod+((x/2*2-1)*m+y)%mod)*(y/2)%mod*inv%mod;
	}
	else 
	{
		st1=(1+y)*(y/2+1)%mod*inv%mod;
		st2=(m+2+m+y-1)*(y/2)%mod*inv%mod;
		ed1=(((x/2*2-2)*m+1)%mod+((x/2*2-2)*m+y)%mod)*(y/2+1)%mod*inv%mod;
		ed2=(((x/2*2-1)*m+2)%mod+((x/2*2-1)*m+y-1)%mod)*(y/2)%mod*inv%mod;	
	}
	int ans=(st1+st2+ed1+ed2)*(x/2)%mod*inv%mod;
	if(x%2)
	{
		if(y%2==0)ans=(ans+(((x-1)*m+1)%mod+((x-1)*m+y-1)%mod)*(y/2)%mod*inv%mod)%mod;	
		else ans=(ans+(((x-1)*m+1)%mod+((x-1)*m+y)%mod)*(y/2+1)%mod*inv%mod)%mod;
	} 
	return ans;
}
signed main()
{
	cin>>n>>m>>q;	
	while(q--)
	{
		int a,b,c,d;cin>>a>>b>>c>>d;
		cout<<(f(b,d)-f(b,c-1)-f(a-1,d)+f(a-1,c-1)+mod+mod)%mod<<endl;
	}
	return 0;
}
posted @ 2022-09-19 22:42  lnwhl  阅读(88)  评论(1编辑  收藏  举报