xcpc近年铜牌题补题路

放弃幻想,准备打铁
随缘补题,学业繁重,补了就更.

45届上海站(2020)

4题铜牌,B,D,G,M
G. Fibonacci
链接
xcpc近年铜牌题补题路_第1张图片
鉴定为纯纯签到
给一个斐波那契数列,定义一个二元函数 g ( x , y ) g(x,y) g(x,y), x ∗ y x*y xy是偶数的时候,返回1,其他情况返回0
计算 ∑ i = 1 n ∑ j = 1 n g ( f i , f j ) \sum_{i=1}^n \sum_{j=1}^ng(f_i,f_j) i=1nj=1ng(fi,fj), f i f_i fi是斐波那契数列的第 i i i项.
观察斐波那契数列可知,第 3 ∗ i 3*i 3i项必定是一个偶数.
考虑所有有序二元对是 n ∗ ( n − 1 ) / 2 n*(n-1)/2 n(n1)/2,再考虑只包含奇数的对 m ∗ ( m − 1 ) / 2 m*(m-1)/2 m(m1)/2
二者相减就是 x ∗ y x*y xy是偶数的对.
只需要算出前n项斐波那契,奇数的个数m即可.
偶数有: n / 3 n/3 n/3个,奇数就有: n − n / 3 n-n/3 nn/3个.

/*
Tonight I wanna drown in an ocean of you
*/
#include
using namespace std;
const int maxn = 1e6+5;
const int INF = 1e9+7;
typedef long long ll;
typedef pair<int,int> pii;
#define all(a) (a).begin(), (a).end()
#define pb(a) push_back(a)
vector<int> G[maxn];
int main(){
    ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	ll n;cin>>n;
	ll m = n - n/3;
	ll ans = n*(n-1)/2 - m*(m-1)/2;
	cout<<ans<<"\n"; 
}

M. Gitignore
链接
阅读理解题。
Your git project (you don’t need to be familiar with git to solve this problem) has some files that should be ignored from synchronizing. You need to calculate the minimum number of lines needed for gitignore.

Formally, your project is a folder. A folder can have files and sub folders. There are no empty folders (i.e. folders without any files or sub folders inside). Initially, the git software will synchronize all the files in your project. However, you can specify some files and folders in the settings (which is called gitignore) to exclude them from synchronizing. For each line in gitignore, you can specify either a file or all the files in a folder. You can not ignore the whole project folder (i.e. an empty line in gitignore).

You are given paths for all the files in the project and whether they should be ignored or shouldn’t. Your task is to calculate the minimum number of lines for gitignore.
题意:在git项目中,一般地,会同步掉你项目里面所有的文件夹。然而,你可以通过一个指令指定那些文件夹你不希望被同步的。
然后给出n行文件夹,是说这些文件夹是要被忽略的,然后再给 m m m行,那些是不能被忽略的。
问你最少忽略多少个文件夹。
思路:文件夹形成了一个树形结构,首先遍历一遍m个要保护的文件夹,把路径上的节点都标记上.
然后遍历n个要被忽略的文件夹,显然如果移动到了一个要保护文件夹的路径上,那么现在还不能删除.
如果第一次移动到了一个不曾被保护的路径上,那么显然我们可以把它删掉.
如果有后续节点访问到了删掉的节点上,事实上不用删了,那么我们认为操作数就减少了1.

/*
Tonight I wanna drown in an ocean of you
*/
#include
using namespace std;
const int maxn = 1e6+5;
const int INF = 1e9+7;
typedef long long ll;
typedef pair<int,int> pii;
#define all(a) (a).begin(), (a).end()
#define pb(a) push_back(a)
vector<int> G[maxn];
int main(){
    ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int T;cin>>T;
	while(T--){
		int n,m;cin>>n>>m;
		vector<string> s1(n),s2(m);
		map<string,int> protect;
		for(int i=0;i<n;i++) cin>>s1[i];
		for(int i=0;i<m;i++) cin>>s2[i];
		for(int i=0;i<m;i++){
			string s = "";
			for(auto ch : s2[i]){
				if(ch=='/') protect[s] = 1;
				s+=ch;
			}
		}
		map<string,int> vis;
		int ans = n;
		for(int i=0;i<n;i++){
			string s = "";
			for(auto ch : s1[i]){
				if(ch=='/'&&!protect[s]){
					if(!vis[s]) vis[s] = true;
					else{
						ans--;break;
					}
				}
				s+=ch;
			}
		}
		cout<<ans<<"\n";
	}
}

B. Mine Sweeper II
给你两张扫雷图,每个不是地雷点的贡献计算为:八连通格内地雷数目.
你可以更改B地图中一半的格子,构造出一种方案,使得和A中的贡献一样.
一个找规律题.
考虑一个地雷对8连通空白格的贡献,在一个地雷旁边,每有一个白格子,就会对应有一个贡献。如果把这个地雷换成空白格,而原本空白格换成地雷,在这个8连通格子内贡献仍然是不变的。
考虑把这个结论推广,因为很像二分图那样的东西.考虑地图中所有的空白格和地雷互相替换,
比如
000 000 000 111 111 111
010 010 010 101 101 101
000 000 000 111 111 111
实际证明不怎么会,可以感性证明一下.考虑下原本贡献如何计算,可以认为是八连通内,地雷的点向周围白格子连边而已,每有一条连边,就会有一点贡献.
现在,只是交换了连边的方向,并不影响边的数目,所以总的数目不变.
那么新增的地雷,新增的空白格,在原本的图中原本就对应空白格-地雷,所以也不会增加。
那么,原本题目只能更改一半的点就图穷匕见了.要么是把B改造成原本那个图,要么把B改造成那个翻转的图,这是一定合法的.
首先,我们尝试把B直接强行改成A,如果不行,说明要改的点 c n t cnt cnt一定大于 n ∗ m / 2 n*m/2 nm/2,此时我们尝试改造那个全部反过来的图,需要改的点是 n ∗ m − c n t n*m-cnt nmcnt一定小于 n ∗ m / 2 n*m/2 nm/2.

/*
Tonight I wanna drown in an ocean of you
*/
#include
using namespace std;
const int maxn = 1000+5;
const int INF = 1e9+7;
typedef long long ll;
typedef pair<int,int> pii;
#define all(a) (a).begin(), (a).end()
#define pb(a) push_back(a)
vector<int> G[maxn];
char mp[maxn][maxn];
char re[maxn][maxn];
char B[maxn][maxn];
int main(){
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);
	for(int i=1;i<=n;i++) scanf("%s",B[i]+1);
	int cnt = 0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(mp[i][j]=='X') re[i][j]='.';
			else re[i][j] = 'X';
			cnt += (mp[i][j]!=B[i][j]);
		}
	}
	if(cnt<=n*m/2){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++) cout<<mp[i][j];
			cout<<"\n";
		}
	}
	else{
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++) cout<<re[i][j];
			cout<<"\n";
		}
	}
}

D. Walker
有一个线段 [ 0 , n ] [0,n] [0,n],有两个人,位置分别是 p 1 , p 2 p1,p2 p1,p2,速度分别是 v 1 , v 2 v1,v2 v1,v2,不能走出线段外面.
转向不需要时间,问你最短多少时间,让这两个人走过的路程覆盖掉整个线段。
显然,线段被分为了三段
假设第一个人(左边),站在B,第二个人(右边)站在C点,让起点是A,终点是D.
假设第一个人是 x x x,第二个是 y y y
讨论以下几种情况.
y y y走完CD后,从D向A走.
首先算出时间 t 1 = C D / v y t1=CD/v_y t1=CD/vy,然后得到 x x x的位置.
i f ( t 1 ∗ v x > = A B ) if(t1*v_x>=AB) if(t1vx>=AB) p o s x = t 1 ∗ v x − A B posx=t1*v_x-AB posx=t1vxAB
否则 p o s x = A B − t 1 ∗ v x 否则posx=AB-t1*v_x 否则posx=ABt1vx
之后,只要 p o s x < n posxposx<n,那么就是两者相碰,不然就是直接走出去了.
然后再讨论 x x x走完AB,y走完 C D CD CD的情况
然后就是两个人直接穿过去的情况,
就是 y y y走CA, x x x B D BD BD的情况.
为什么没有代码了,博主退役了

你可能感兴趣的:(算法,图论,c++)