AtCoder Beginner Contest 191
A
…
B
…
C
给出一张n*m的黑白染色的网格图,保证所有黑格子连通,所有白格子也连通
统计黑格子组成的多边形有几条边
多边形边数与顶点数相同,只需统计顶点数
对于每个点判断其是否为顶点即可
不是
是
不是
不存在
是
不是
对于每个格点,判断周围四个格子中黑格子个数是否为1或3即可
(由于题目保证黑格子连通和白格子连通,有一种染色方式不存在)
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
const int N = 1005;
string st;
int a[N][N],n,m,cnt=0;
int main()
{
cin>>n>>m;
for (int i=1;i<=n;++i)
{
cin>>st;
for (int j=1;j<=m;++j)
if (st[j-1]=='.') a[i][j]=0;else a[i][j]=1;
}
for (int i=1;i<n;++i)
{
for (int j=1;j<m;++j)
{
int c=a[i][j]+a[i+1][j]+a[i][j+1]+a[i+1][j+1];
if (c==1 || c==3) ++cnt;
}
}
cout<<cnt<<endl;
return 0;
}
D
给出一个圆的圆心坐标与其半径
统计在圆内或圆上的整点个数
卡精度,注意到输入的数最多只有四位小数,全部乘以10000后再做
注意到半径较小,枚举横坐标,再计算纵坐标即可
为避免精度误差,可以用二分或倍增来计算纵坐标范围
E
给出一张有向图,对于每个点,统计经过它的最短的环的长度
注意到没有负权,对于每个起点都跑一次dijkstra即可
F
给出一些正整数,两种操作
1.将x,y从中删去,再加入min(x,y)
2.将x,y从中删去,再加入gcd(x,y)
重复进行操作,直到只剩下一个数
问最后剩下的数有几种
注意到先进行操作1再进行操作2可以改为先操作2再操作1
那么可以将所有的操作1留到最后再做,并且操作1一定会保留最小值
问题转化为只用操作2,能造出几种最小值
注意到若y%x=0,那么有min(x,y)=x=gcd(x,y)
即如果y%x=0,可以用操作1代替操作2
若
y
%
x
≠
0
y \% x \neq 0
y%x=0 ,那么gcd(x,y)<=min(x,y)/2
若将可替换的操作2全部替换,发现与答案有关的操作2个数为 log n
注意到这个性质并没有什么用
观察到gcd一定是其中某个数的因子,所以gcd的种数 ≤ n ∗ m a x ( a i ) 1 2 \leq n*max(a_i)^{\frac{1}{2}} ≤n∗max(ai)21
并且只有该gcd的倍数才会产生这个gcd,所以求其所有倍数的gcd,判断是否与其相等即可
对于每个 a i a_i ai ,枚举所有因子并对其做一次贡献即可
中间过程产生的gcd可以用map存储
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
const int N = 1500005;
ll getgcd(ll x,ll y) {return (y==0) ? x : getgcd(y,x%y);}
int a[N],n,ans;
map <int,int> mp;
void ins(int x,int t)
{
if (!mp[x]) mp[x]=t;
else mp[x]=getgcd(mp[x],t);
}
int main()
{
cin>>n; for (int i=1;i<=n;++i) scanf("%d",&a[i]);
sort(a+1,a+1+n);
for (int i=1;i<=n;++i)
{
for (int j=1;j*j<=a[i];++j)
if (a[i]%j==0)
{
ins(j,a[i]);
ins(a[i]/j,a[i]);
}
}
ans=0;
for (auto it:mp) ans+=(it.first==it.second && it.first<=a[1]);
cout<<ans<<endl;
return 0;
}