• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
nannandbk
博客园    首页    新随笔    联系   管理    订阅  订阅
AtCoder Beginner Contest 302 ABCDEF

AtCoder Beginner Contest 302

A - Attack

Problem Statement

题意:敌人有\(A\)的耐力值,每次攻击敌人可以减少\(B\)的耐力值,问多少次敌人耐力值\(<=0\)?

Solution

题解:\(\dfrac{a}{b}\)上取整。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
	ll a,b;
	cin>>a>>b;
	if(a%b==0)
		cout<<a/b<<endl;
	else cout<<a/b+1<<endl;
	return 0;
}

B - Find snuke

Problem Statement

题意:给你一个\(n\)行\(m\)列矩阵,里面都是小写英文字母,输出在同一直线上出现的\(snuke\)。输出坐标。

Solution

题解:遍历一遍,找到\(s\)的位置进行\(check\)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 110;
char a[N][N];
int n,m;
bool check(int i,int j)
{
	bool ok = false;
	if(i-4>=1)
		if(a[i-1][j]=='n'&&a[i-2][j]=='u'&&a[i-3][j]=='k'&&a[i-4][j]=='e')
		{
			ok = true;
			cout<<i<<" "<<j<<endl;
			cout<<i-1<<" "<<j<<endl;
			cout<<i-2<<" "<<j<<endl;
			cout<<i-3<<" "<<j<<endl;
			cout<<i-4<<" "<<j<<endl;
			return ok;
		}
	if(i+4<=n)
		if(a[i+1][j]=='n'&&a[i+2][j]=='u'&&a[i+3][j]=='k'&&a[i+4][j]=='e')
		{
			ok = true;
			cout<<i<<" "<<j<<endl;
			cout<<i+1<<" "<<j<<endl;
			cout<<i+2<<" "<<j<<endl;
			cout<<i+3<<" "<<j<<endl;
			cout<<i+4<<" "<<j<<endl;
			return ok;
		}
	if(j-4>=1)
		if(a[i][j-1]=='n'&&a[i][j-2]=='u'&&a[i][j-3]=='k'&&a[i][j-4]=='e')
		{
			ok = true;
			cout<<i<<" "<<j<<endl;
			cout<<i<<" "<<j-1<<endl;
			cout<<i<<" "<<j-2<<endl;
			cout<<i<<" "<<j-3<<endl;
			cout<<i<<" "<<j-4<<endl;
			return ok;
		}
	if(j+4<=m)
		if(a[i][j+1]=='n'&&a[i][j+2]=='u'&&a[i][j+3]=='k'&&a[i][j+4]=='e')
		{
			ok = true;
			cout<<i<<" "<<j<<endl;
			cout<<i<<" "<<j+1<<endl;
			cout<<i<<" "<<j+2<<endl;
			cout<<i<<" "<<j+3<<endl;
			cout<<i<<" "<<j+4<<endl;
			return ok;
		}
	if(i-4>=1&&j-4>=1)
		if(a[i-1][j-1]=='n'&&a[i-2][j-2]=='u'&&a[i-3][j-3]=='k'&&a[i-4][j-4]=='e')
		{
			ok = true;
			cout<<i<<" "<<j<<endl;
			cout<<i-1<<" "<<j-1<<endl;
			cout<<i-2<<" "<<j-2<<endl;
			cout<<i-3<<" "<<j-3<<endl;
			cout<<i-4<<" "<<j-4<<endl;
			return ok;
		}
	if(i+4<=n&&j+4<=m)
		if(a[i+1][j+1]=='n'&&a[i+2][j+2]=='u'&&a[i+3][j+3]=='k'&&a[i+4][j+4]=='e')
		{
			ok = true;
			cout<<i<<" "<<j<<endl;
			cout<<i+1<<" "<<j+1<<endl;
			cout<<i+2<<" "<<j+2<<endl;
			cout<<i+3<<" "<<j+3<<endl;
			cout<<i+4<<" "<<j+4<<endl;
			return ok;
		}
	if(i-4>=1&&j+4<=m)
		if(a[i-1][j+1]=='n'&&a[i-2][j+2]=='u'&&a[i-3][j+3]=='k'&&a[i-4][j+4]=='e')
		{
			ok = true;
			cout<<i<<" "<<j<<endl;
			cout<<i-1<<" "<<j+1<<endl;
			cout<<i-2<<" "<<j+2<<endl;
			cout<<i-3<<" "<<j+3<<endl;
			cout<<i-4<<" "<<j+4<<endl;
			return ok;
		}
	if(i+4<=n&&j-4>=1)
		if(a[i+1][j-1]=='n'&&a[i+2][j-2]=='u'&&a[i+3][j-3]=='k'&&a[i+4][j-4]=='e')
		{
			ok = true;
			cout<<i<<" "<<j<<endl;
			cout<<i+1<<" "<<j-1<<endl;
			cout<<i+2<<" "<<j-2<<endl;
			cout<<i+3<<" "<<j-3<<endl;
			cout<<i+4<<" "<<j-4<<endl;
			return ok;
		}

	return ok;

}
int main()
{
	cin>>n>>m;
	for(int i = 1;i<=n;i++)
		for(int j = 1;j<=m;j++)
			cin>>a[i][j];
	for(int i = 1;i<=n;i++)
	{
		for(int j = 1;j<=m;j++)
		{
			if(a[i][j]=='s')
			{
				if(check(i,j))return 0;
			}
		}
	}
	return 0;
}

C - Almost Equal

Problem Statement

题意:给你\(N\)个长度为\(M\)的字符串,问你能否对这些字符串重新排列,使得第\(i\)个和第\(i+1\)个字符串只有一个字母不一样,可以输出\(Yes\),否则\(No\).

Solution

题解:因为注意到\(N\)范围很小,可以直接暴力\(dfs\),先进性一个全排列,每次\(check\)是否满足。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m,cnt;
const int N = 10;
string s[N];
int a[N];
bool vis[N];
map<int,string>mp;
bool yes;
void dfs(int step)
{
	if(yes)return;
	if(step>n)
	{
		bool ok = true;
		for(int i = 1;i<n;i++)
		{
			int c = 0;
			string t = mp[a[i]];
			string t2 = mp[a[i+1]];
			for(int j = 0;j<m;j++)
			{
				if(t[j]!=t2[j])c++;
			}
			if(c!=1)
			{
				ok = false;
				break;
			}
		}
		if(ok)yes = true;
		return;
	}	
	for(int i = 1;i<=n;i++)
	{
		if(!vis[i])
		{
			a[step] = i;
			vis[i] = true;
			dfs(step+1);
			vis[i] = false;
			a[step] = 0;
		}
	}
}
int main()
{
	cin>>n>>m;
	for(int i = 1;i<=n;i++)
		cin>>s[i],mp[++cnt] = s[i];
	dfs(1);
	if(yes)cout<<"Yes\n";
	else cout<<"No\n";
	return 0;
}

D - Impartial Gift

Problem Statement

题意:要为两个人选礼物,从\(N\)个候选中选一个给\(A\),从\(M\)个候选中选一个给\(B\),问两个的价值相差不超过\(D\),问你两个礼物总和最大为多少?

Solution

题解:排序+双指针。因为我们优先选价值高的,如果不满足价值差小于\(D\)就移动价值大的那个指针,因为这个时候移动小的只会更厘普。

注意\(A,B\)的范围,小心爆\(long long\)

#include<bits/stdc++.h>
using namespace std;
__int128 read()
{
	__int128 f = 1, w = 0;
	char ch = getchar();
	while (ch < '0' || ch>'9')
	{
		if (ch == '-')
			f = -1;
		ch = getchar();
	}
	while (ch <= '9' && ch >= '0')
	{
		w = w * 10 + ch - '0';
		ch = getchar();
	}
	return f * w;
}

void print(__int128 x)
{
	if (x < 0)
	{
		putchar('-');
		x = -x;
	}
	if (x > 9)print(x / 10);
	putchar(x % 10 + '0');
}

typedef __int128 ll;
const int N = 2e5+10;
ll n,m,D;
ll a[N],b[N];
bool cmp(ll a,ll b)
{
	return a>b;
}
int main()
{
	n = read(),m = read(),D = read();
	for(int i = 1;i<=n;i++)
		a[i] = read();
	for(int i = 1;i<=m;i++)
		b[i] = read();
	sort(a+1,a+1+n,cmp);
	sort(b+1,b+1+m,cmp);
	ll c = 1,d = 1;
	bool ok = false;
	ll ans = 0;
	while(c<=n&&d<=m)
	{

		if((a[c]-b[d]>=0&&a[c]-b[d]<=D)||(b[d]-a[c]>=0&&b[d]-a[c]<=D))
		{
			ok = true;
			ans = a[c]+b[d];
			break;
		}
		else
		{
			if(a[c]>b[d])c++;
			else d++;
		}
	}
	if(ok)
		print(ans);
	else cout<<-1<<endl;
	return 0;
}

E - Isolation

Problem Statement

题意:给你一个无向图,\(N\)个点,编号\(1\)到\(N\),并且初始状态没有边。

给你\(Q\)个询问,每次询问输出当前孤立的点的数目。

\(1\) $ u$ $ v$ :连接\(uv\)

$2 $ $ v$ :删除和\(v\)相连的所有边

Solution

题解:用\(set\)存边,先说操作一:对于点x,y,连接他们两个,如果set[x].size()==0的话,那现在连上了,那答案-1,同样对于\(y\)也是。对于操作二:删边操作。我们遍历该点连的所有边,用lower_bound直接erase掉对应点和\(x\)的边,如果删完之后edge[y].size()变为0了,那答案+1,最后如果对于操作的点\(x\),如果edge[x].size是大于0的,那答案-1,edge[x].clear。解决。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5+10;
int cnt;
map<pair<int,int>,int>mp;
set<int>edge[N];
int main()
{
	int n,q;
	cin>>n>>q;
	cnt = n;
	for(int i = 1;i<=q;i++)
	{
		int op;
		cin>>op;
		if(op==1)
		{
			int x,y;
			cin>>x>>y;	
			cnt -= edge[x].empty(),cnt-=edge[y].empty();
			edge[x].insert(y);
			edge[y].insert(x);
			cout<<cnt<<endl;
		}
		else
		{
			int x;
			cin>>x;
			for(auto y:edge[x])
			{
				edge[y].erase(edge[y].lower_bound(x));
				cnt += edge[y].empty();
			}
			if(edge[x].size())
				cnt++,edge[x].clear();
			cout<<cnt<<endl;
		}
	}
	return 0;
}

F - Merge Set

Problem Statement

题意:给你\(N\)个集合,我们每次选2个集合进行合并,这两个集合要至少有一个一样的元素才能合并,问至少合并多少次能使得集合中同时包含\(1\)和\(M\)。

Solution

思路:是01bfs。我们考虑把\(N\)个集合看成\(N\)个点,\(M\)个元素看成\(M\)个点,建图跑最短路。当前集合到集合内元素的距离设为0,集合元素到集合的距离设为1,跑bfs或者dijkstra都可以。因为是求合并次数,最后答案-1.

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+10;
struct Node
{
	int y,v;
	Node(int _y,int _v){y = _y;v = _v;};
};
set<pair<int,int>>q;
vector<Node>edge[N*2];
int n,m,k, dist[N*2];
inline void dijkstra(int s)
{
	memset(dist,127,sizeof(dist));
	dist[s] = 0;
	q.clear();
	for(int i = 1;i<=n+m;i++)
	{
		q.insert({dist[i],i});
	}
	while(!q.empty())
	{
		int x = q.begin()->second;//离起点最近的点的下标
		q.erase(q.begin());
		for(auto i:edge[x])
		{
			if(dist[x]+i.v<dist[i.y])
			{
				q.erase({dist[i.y],i.y});
				dist[i.y]= dist[x]+i.v;
				q.insert({dist[i.y],i.y});
			}
			
		}
	}
}


int main()
{
	cin>>n>>m;
	for(int i = 1;i<=n;i++)
	{
		int sz;
		cin>>sz;
		for(int j = 1;j<=sz;j++)
		{
			int x;
			cin>>x;
			edge[i].push_back(Node(x+n,0));
			edge[x+n].push_back(Node(i,1));
		}
	}
	dijkstra(1+n);
	ll ans = dist[m+n];
	if(ans>(1<<30))ans= 0;
	cout<<ans-1<<endl;
	return 0;
}
posted on 2023-06-17 08:54  nannandbk  阅读(40)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3