AtCoder Beginner Contest 191 题解

题目地址

A,B不说了

C

容易发现这个多边形有多少个边就会有多少个角
即求一下这个图里面有多少个直角
通过观察容易发现,当图里面有直角时
满足对于\((i,j)\),至少有两个方向,使得元素不等于\(a[i][j]\)
具体看代码即可

#include <bits/stdc++.h>
using namespace std;
const int N = 101;
int h, w;
char a[N][N];
signed main()
{
	scanf("%d%d",&h,&w);
	for(int i = 1;i <= h; i++) scanf("%s",a[i] + 1);
	int ans = 0;
	for(int i = 1;i <= h; i++)
	for(int j = 1;j <= w; j++)
	{
		if(a[i][j] == '#')
		{
			if(a[i - 1][j] == '.' && a[i][j - 1] == '.') ++ ans;
			if(a[i][j - 1] == '.' && a[i + 1][j] == '.') ++ ans;
			if(a[i + 1][j] == '.' && a[i][j + 1] == '.') ++ ans;
			if(a[i][j + 1] == '.' && a[i - 1][j] == '.') ++ ans;
		}
		if(a[i][j] == '.')
		{
			if(a[i - 1][j] == '#' && a[i][j - 1] == '#') ++ ans;
			if(a[i][j - 1] == '#' && a[i + 1][j] == '#') ++ ans;
			if(a[i + 1][j] == '#' && a[i][j + 1] == '#') ++ ans;
			if(a[i][j + 1] == '#' && a[i - 1][j] == '#') ++ ans;
		}
	}
	cout << ans;
}

D

思路很简单,直接定一维枚举\(x\),观察在\(x\)固定下来有多少个符合条件的整点\(y\)即可,最后累加起来便是答案
直接double会WA,所以需要用long double来卡精度,同时注意可以将\(R\)加上\(10^{-14}\),来防止精度的损失
之后有个小技巧是利用系统自带函数\(ceil\)\(floor\)分别实现向上取整和向下取整

#include<bits/stdc++.h>
using namespace std;
#define debug(x) cout<<#x<<"="<<x<<endl
#define lowbit(x) x&(-x)
#define pii pair<int,int>
#define mk make_pair
#define ll long long
#define lb long double
#define rs p<<1|1
#define ls p<<1
const int maxn = 1e6 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
inline ll read()
{
    ll p=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){p=(p<<1)+(p<<3)+(c^48),c=getchar();}
    return f*p;
}

void solve()
{
    lb x, y, R;
	cin >> x >> y >> R;
	R += 1e-14;
	ll ans = 0;
	for(int i = ceil(x - R);i <= floor(x + R); i++)
	{
		lb t, b;
		t = y + sqrt(R * R - (x - i) * (x - i));
		b = y - sqrt(R * R - (x - i) * (x - i));
		ans += floor(t) - ceil(b) + 1; 
	} 
	cout << ans << endl;
}

signed main()
{
	int t = 1;
	while(t --) solve();
}


E

直接多点跑堆优化的dij最短路即可,注意判一下重边就好

#include <bits/stdc++.h>
#define inf 1e9
using namespace std;
const int N = 2e3 + 101; 
struct Edge{
	int nex, to, dis;
}edge[N*2];
int tot, head[N], dis[N];
int dist[N][N], ans[N], vis[N];
struct node{
	int u, dis;
	bool operator < (const node &a) const{
	    return dis > a.dis;
	}
};
priority_queue<node>q;
int n, m;

void add(int from,int to,int dis)
{
	edge[++ tot].nex = head[from];
	edge[tot].to = to;
	edge[tot].dis = dis;
	head[from] = tot;
}

void dij(int s)
{
	for(int i = 1;i <= n; i++) dis[i] = inf, vis[i] = 0;
	dis[s] = 0;q.push((node){s,0});
	while(!q.empty())
	{
		int u = q.top().u;
		q.pop();
		if(vis[u]) continue;
		vis[u] = 1;
		for(int i = head[u];i;i = edge[i].nex)
		{
			int v = edge[i].to;
			if(dis[v] > dis[u] + edge[i].dis)
			{
				dis[v] = dis[u] + edge[i].dis;
				q.push((node){v,dis[v]});
			}
		}
	}
	for(int j = 1;j <= n; j++) dist[s][j] = dis[j];
}

signed main()
{
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n; i++)
	    for(int j = 1;j <= n; j++)
	        dist[i][j] = inf, ans[i] = inf;
	for(int i = 1;i <= m; i++)
	{
		int u, v, w;scanf("%d%d%d",&u,&v,&w);
		add(u,v,w);
		if(u == v) ans[u] = min(ans[u],w);
	} 
	for(int i = 1;i <= n; i++) dij(i);
	for(int i = 1;i <= n; i++)
	for(int j = 1;j <= n; j++)
	    if(i != j) ans[i] = min(ans[i],dist[i][j] + dist[j][i]);
	for(int i = 1;i <= n; i++) 
	    printf("%d\n",ans[i] == inf ? -1 : ans[i]);
}

F

非常不错的一道思维题
首先我们容易发现一条性质\(gcd(a,b)<=min(a,b)\)
这决定了我们的答案的上界是数列\(a\)的最小值
首先我们可以将数列\(a\)从小到大进行排序
其次对于每一个小于\(a[1]\)\(k\),什么时候它可以成为合法的解
当存在a数列的一个子集,满足\(gcd(a_i,a_j,a_k....,a_l)=k\)时符合条件
更深层次容易发现,即为所有含有\(k\)因子的数\(a_i\)\(gcd\)\(k\) (关键性质)
我们设\(f[k]\)为含有因子\(k\)的所有数\(a_i\)\(gcd\)
最后的答案\(ans\)即为所有满足\(f[k]=k\)\(k\)的个数
关于\(f[k]\)的获得,可以通过开一个\(map\),然后扫一遍数组即可(具体详见代码)
其中容易发现\(k\)最坏级别为\(O(n\sqrt{max(a_i)})\)是可以承受的
最后开set枚举k,看符合条件\(++ans\)即可

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 101; 
map<int,int>f;
int n, a[N];
set<int>s;
set<int>::iterator it;
signed main()
{
	scanf("%d",&n);
	for(int i = 1;i <= n; i++) scanf("%d",&a[i]);
	sort(a + 1,a + n + 1);
	int ans = 1;
	for(int i = 1;i <= n; i++)
		for(int j = 1;j * j <= a[i]; j++)
		{
			if(a[i] % j == 0)
			{
				if(!f[j] && j < a[1]) f[j] = a[i];
				if(j < a[1]) f[j] = __gcd(f[j],a[i]),s.insert(j);
				if(j * j == a[i]) continue;
				if(!f[a[i]/j] && a[i]/j < a[1]) f[a[i]/j] = a[i];
				if((a[i]/j) < a[1]) f[a[i]/j] = __gcd(a[i],f[a[i]/j]),s.insert(a[i]/j); 
			} 
		}
	for(it = s.begin();it != s.end(); it++) 
	    if(f[*it] == *it) ++ ans;
 	cout << ans;
}
 
posted @ 2021-02-12 20:05  zjz2333  阅读(199)  评论(0编辑  收藏  举报