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;
}