1. 程式人生 > 其它 >Codeforces 766 Div.2題解

Codeforces 766 Div.2題解

Codeforces 766 Div.2題解

A

題意:給你一個矩陣,每一次操作你可以選擇一個字元為B的位置(x , y),可以使得x行字元都變為B,或者是讓y行字元都變成B

現在問你什麼情況下可以使 (x1,y1) 所在的位置字元為B

簡單分析一下:

①當(x1,y1)就是B的時候操作次數是0次

②當矩陣中不存在B的時候,不存在答案,為-1

③當x1行或者y1列存在B,那麼操作次數是1次

④否則,就需要兩次,從非x1行,非y1列的地方隨便操作一個B,可以使得x1行 or y1列中出現一個B,那麼就變成了③的情況,答案是2

檢視程式碼

#include<iostream>
#include <vector>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 55;
char a[MAXN][MAXN];
/*
4 10 1
0 3 4 8
5 8 3 6

*/
void solve()
{
	int n,m,x,y;
	scanf("%d %d %d %d",&n,&m,&x,&y);
	int f = 0;
	for(int i = 1;i <= n;++i)	scanf("%s",a[i] + 1);
	for(int i = 1;i <= n;++i)
	for(int j = 1;j <= m;++j)
	{
		if(a[i][j] == 'B')	{
			f = 1;
			break;
		}
	}
	if(!f)	{
		puts("-1");
		return ;
	}
	if(a[x][y] == 'B')
	{
		puts("0");
		return ;
	}
	for(int i = 1;i <= n;++i)
	if(a[i][y] == 'B')	{
		puts("1");
		return ;
	}
	for(int i = 1;i <= m;++i)
	{
		if(a[x][i] == 'B')	{
			puts("1");
			return ;
		}
	}
	puts("2");
}
int main()
{
	int t = 1;
	scanf("%d",&t);
	while(t--)
	solve();
	return 0; 
}

B

題意:

給你一個N * M的矩陣,Tina可以選擇其中的k個位置(k∈[0,n * m - 1]),使得這k個位置染色成為粉色,Rahul不會坐在粉色的位置,而Tina可以坐在任何的位置上。然後Rahul和Tina輪流選擇位置,Rahul想要最後同Tina坐的儘可能近,而Tina想要和他坐的儘可能遠,問你若他們兩個都非常聰明,k∈[0 , n * m - 1]這時候的最遠距離分別是多少

分析:

①由於k是在 0 ~ n * m - 1範圍之內的,那麼Rahul會將所有的位置都坐一遍

②由於Tina要坐的和Rahul儘可能的遠,那麼最優的情況就是選擇矩陣的四個角落(很簡單的貪心吧)

③K越大,Tina和Rahul的距離會盡可能的遠,也就是說答案是遞增的

那麼我們就可以將所有的位置都遍歷一遍,然後和四個角的哈密頓距離進行對比,取最大的那個,最後將陣列排序,輸出前n * m個數字即可

檢視程式碼

#include<iostream>
#include <vector>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 55;
char a[MAXN][MAXN];
/*
4 10 1
0 3 4 8
5 8 3 6

*/
vector<int> ans;
int dis(int x,int y,int x1,int y1)
{return abs(x - x1) + abs(y - y1);}
void solve()
{
	ans.clear();
	int n,m;
	scanf("%d %d",&n,&m);
	for(int i = 1;i <= n;++i)
	for(int j = 1;j <= m;++j)
	{
		ans.push_back(max(max(dis(i,j,1,1),dis(i,j,n,m)),max(dis(i,j,1,m),dis(i,j,n,1))));
	}
	sort(ans.begin(),ans.end());
	int siz = n * m - 1;
	for(int i = 0;i <= siz;++i)
	printf("%d%c",ans[i], " \n"[i == siz]);
}
int main()
{
	int t = 1;
	scanf("%d",&t);
	while(t--)
	solve();
	return 0; 
}

C

題意:

給你一棵樹,你要給所有的邊新增一個權值,使得每一個長度 <= 2的路徑權值和都是一個質數

分析:

我們可以直接看到第三個樣例,它為什麼不能夠構成一個Prime樹。

①分析可知,兩個非2的素數進行相加操作,得到的數字一定不是質數

②如果一個節點的度為3,那麼勢必需要存在兩個2,才可以使得其中的兩條邊和為質數,但是那兩條2的邊形成的不是質數,因此存在節點度數 >= 3的樹就直接輸出-1

③可以知道這顆樹是一個鏈,我們只需要從度數為0的點開始,依次對各條邊進行賦值即可(2,5,2,5,2,5,2....依次)

程式碼有點亂,可以看看正解的程式碼

檢視程式碼

#include<iostream>
#include <vector>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 7;
bool prime[MAXN * 16 + 1];
int p[MAXN],top = 0;
/*
4 10 1
0 3 4 8
5 8 3 6
*/
vector<int> ans,tmp;
void ini()
{
	top = 0;
	int MAX = 1e6;
	for(int i = 2;i < MAX;++i)
	{
		if(!prime[i])	p[++top] = i;
		for(int j = 1;j <= top && 1ll * p[j] * i < MAX;++j)
		{
			prime[p[j] * i] = 1;
			if(i % p[j] == 0)	break;
		}
	}
}
struct node{
	int x,id;
	node(int x = 0,int id = 0):x(x),id(id){}
};
int deg[MAXN],a[MAXN];
vector<node> g[MAXN];
/*
1
6
3 4
4 5
5 6
2 1
2 3
*/
struct no{
	int x,y,id;
}all[MAXN];
void dfs(int x,int fa,int ls)
{
	for(int i = 0;i < g[x].size();++i)
	{
		node t = g[x][i];
		if(t.x == fa)	continue;
		if(ls == 2)
		a[t.id] = 5;
		else
		a[t.id] = 2;
		dfs(t.x,x,a[t.id]);
	}
}
void solve()
{
	int n;
	scanf("%d",&n);
	for(int i = 1;i <= n;++i)	deg[i] = 0,g[i].clear();
	int f = 0;
	for(int i = 1;i < n;++i)
	{
		int x,y;
		scanf("%d %d",&x,&y);
		deg[x] += 1;
		deg[y] += 1;
		g[x].push_back(node(y,i)),g[y].push_back(node(x,i));
		all[i].id = i;
		all[i].x = x,all[i].y = y;
		if(deg[x] >= 3 || deg[y] >= 3)	f = 1;
	}
	if(f)
	{
		puts("-1");
		return ;
	}
	for(int i = 1;i <= n;++i)
	{
		if(deg[i] == 1)
		{
			for(int j = 1;j < n;++j)
			{
				if(all[j].x == i || all[j].y == i)
				{
					a[all[j].id] = 2;
					dfs(i,0,2);
					for(int j = 1;j < n;++j)
					printf("%d%c",a[j]," \n"[j == n - 1]);
					return ;
				}
			}	
		}
	}
	puts("-1");
}
int main()
{
//	ini();
	int t = 1;
	scanf("%d",&t);
	while(t--)
	solve();
	return 0; 
}

D

題意:

n個數,每一次操作你可以選擇其中的兩個數進行GCD,然後將得到的數字加入到序列的末尾,當然這個數字不能出現在原序列當中,問你最多操作幾次。

分析:

①看到a的最值是1e6我們可以發現這裡面一定有貓膩,那麼我們可以每次對數字i進行判定,看看它能不能加入到我們的序列當中

②如果一個數能夠加入進來,那麼所有在序列中的數字能被這個數取餘為0的,進行GCD操作一定會得到這個數,具體來說就是:

最終的答案就是ans - n

檢視程式碼

#include <iostream>
#include <vector>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 1e6 + 7;
bool vis[MAXN];
bool prime[MAXN];
int p[MAXN],top = 0;
void ini()
{
	for(int i = 2;i < MAXN;++i)
	{
		if(!prime[i])	p[++top] = i;
		for(int j = 1;j <= top && 1ll * p[j] * i < MAXN;++j)
		{
			prime[p[j] * i] = 1;
			if(i % p[j] == 0)	break;
		}
	}
}
/*
2
4 16
*/
int gcd[MAXN];
void solve()
{
	int n;
	scanf("%d",&n);
	for(int i = 1;i <= n;++i)	{
		int x;
		scanf("%d",&x);
		vis[x] = 1;
	}
	int ans = 0;
	for(int i = 1;i <= 1e6;++i)
	{
		for(int j = i;j <= 1e6;j += i)
		if(vis[j])	gcd[i] = __gcd(gcd[i],j);
		ans += gcd[i] == i;
	}
	printf("%d\n",ans - n);
}
int main()
{
//	ini();
	int t = 1;
//	scanf("%d",&t);
	while(t--)
	solve();
	return 0; 
}