Educational Codeforces Round 89 (Rated for Div. 2) A、B、C、D、E、题解

目录

 

1366A. Shovels and Swords

1366B. Shuffle

1366C. Palindromic Paths

1366D. Two Divisors

1366E. Two Arrays


1366A. Shovels and Swords

题意:制造铁楸需要2跟棍子和1个石头,制造剑需要1根棍子和2个石头。现在有A根棍子和B个石头。问能制造多少把剑或铁楸。

思路:先制造其中一种使得A == B,若 A != 0,则可以知道,每3个石头和棍子可以制造两个物品。所以剩下的A块原料每块可以制造2/3个物品,总共A*2/3个物品。

AC代码:

/*---------------------------------
 *File name: A.cpp
 *Creation date: 2020-06-20 21:16
 *Link: 
 *-------------------------------*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define fi first
#define se second
#define pb push_back
#define LL long long
#define PII pair
#define Pque priority_queue 
using namespace std;
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
const LL mod = 1e9 + 7;
const double EPS = 1e-8;

int main(){
	int t;
	cin >> t;
	while(t--){
		int a, b;
		cin >> a >> b;
		if(a > b) swap(a, b);
		int tmp = b - a;
		int ans = 0;
		if(tmp >= a) ans = a, a = 0;
		else a -= tmp, b -= 2 * tmp, ans = tmp;
		if(a != 0) ans += a * 2 / 3;
		cout << ans << endl;
	}
	return 0;
}

1366B. Shuffle

题意:给一个长度为N的数组A,A_x = 1,其余为0。将会进行M次操作,每次操作选定一个区间[L,R] ,可以在区间[L,R]中任意选择两个不同的位置进行交换。问有多少个位置经过操作后有可能为1。

思路:因为只要能让为1的位置与目标位置进行交换答案就能增加1,所以只需要判断A_x可以到达的区间就可以。

AC代码:

#include
#include
#include
using namespace std;

int main(){
	int t;
	scanf("%d", &t);
	while(t--){
		int n, x, m;
		scanf("%d %d %d", &n, &x, &m);
		int L, R;
		L = R = -1;
		while(m--){
			int l, r;
			scanf("%d %d", &l, &r);
			if(L == -1 && l <= x && r >= x) L = l, R = r;
			if(L != -1){
				if(l <= L && r >= L) L = l;
				if(r >= R && l <= R) R = r;
			}
		}
		printf("%d\n", R - L + 1);
	}
	return 0;
}

1366C. Palindromic Paths

题意:给一个N*M的01矩阵,将从点(1,1)到点(N,M)的路径所经过点的值按照顺序写出形成一个01字符串。要求所有路径形成的01字符串都是一个回文串。

思路:按照回文串的定义,起点和终点的值得相等,第一步走到的点和最后一步走开始的点的值要相等,第二步.......简单讲就是,从起点出发,第 i(i\epsilon [0,N-M-2]) 步可能走到的所有点的权值,与从终点出发,第i(i\epsilon [0,N-M-2])步可能走到的点的权值相同。因此第i(i\epsilon [0,N-M-2])步能走到的点只能全为1或0。判断将第 i 步能走到的点的权值置为1好还是置为0好就结束了。

AC代码:

/*---------------------------------
 *File name: A.cpp
 *Creation date: 2020-07-05 03:38
---------------------------------*/
#include
#include
#include
#include
#include
using namespace std;

int main(){
	int t;
	scanf("%d", &t);
	while(t--){
		int n, m;
		scanf("%d %d", &n, &m);
		vector a[n + 1];
		map mp1, mp0;
		for(int i = 1; i <= n; ++i){
			a[i].resize(m + 1);
			for(int j = 1; j <= m; ++j){
				scanf(" %d", &a[i][j]);
				int tmp = i - 1 + j - 1;
				mp1[tmp] += a[i][j];
				mp0[tmp] += a[i][j] ^ 1;
			}
		}
		int ans = 0;
		for(int i = 0; i <= ((n + m - 2) >> 1); ++i){
			int c1, c0;
			c1 = mp0[i] + mp0[n + m - 2 - i];
			c0 = mp1[i] + mp1[n + m - 2 - i];
			if(i == n + m - 2 - i) continue;
			ans += min(c1, c0);
		}
		printf("%d\n", ans);
	}
	return 0;
}

1366D. Two Divisors

题意:给定一个长度为N的数组A,问对于数组中每一个元素X,是否能够找到两个因子D1和D2,使得GCD(D1+D2,X) = 1,D1>1, D2>1。能的话输出因子,不能输出两个-1。

思路:如果将X质因子分解之后,没有两个以上的质因子,则找不到。否则D1的值为除最后一个因子外其他所有质因子的乘积,D2为最后一个质因子。正确性没有证明,感觉上是对的,写了一发A了。

AC代码:

/*---------------------------------
 *File name: A.cpp
 *Creation date: 2020-07-05 03:38
 *Link: 
 *-------------------------------*/
#include
#include
#include
#include
#include
#define fi first
#define se second
#define PII pair
using namespace std;
const int maxn = 1e7 + 5;
 
bool antiprim[maxn];
int prim[maxn];
int cnt = 0;
 
inline void init(){
	antiprim[1] = antiprim[0] = 1;
	for(int i = 2; i < maxn; ++i){
		if(antiprim[i] == 0){
			prim[++cnt] = i;
			for(int j = i + i; j < maxn; j += i) antiprim[j] = 1;
		}
	}
}
 
int main(){
	init();
	int n;
	scanf("%d", &n);
	vector ans;
	for(int i = 0; i < n; ++i){
		int x;
		scanf("%d", &x);
		if(!antiprim[x]) {
			ans.pb(PII(-1, -1));
			continue;
		}
		LL fi, se;
		fi = se = 1;
		int re = 0;
		for(int j = 1; prim[j] * prim[j] <= x; ++j){
			int time = 0;
			bool flag = 0;
			while(x % prim[j] == 0){
				x /= prim[j];
				time++;
				flag = 1;
				fi *= prim[j];
			}
			if(!flag) continue;
			re++;
			if(!antiprim[x]){
				se = x;
				break;
			}
			if(x == 1){
				if(re == 1) {//判断有几个质因子
					se = fi = -1;
					break;
				}
				for(int k = 1; k <= time; ++k) se *= prim[j], fi /= prim[j];//要将最后一个质因子的值赋给D2,同时D1去除掉这个质因子。
				break;
			}
		}
		if(se == fi || se == 1 || fi == 1) se = fi = -1;
		if(fi > se) swap(fi, se);//强迫症需求
		ans.pb(PII(fi, se));
	}
	for(int i = 0; i < n; ++i) printf("%d ", ans[i].fi);
	printf("\n");
	for(int i = 0; i < n; ++i) printf("%d ", ans[i].se);
	printf("\n");
	return 0;
}

1366E. Two Arrays

题意:给定一个长度为N的数组A和长度为M的数组B,问能否将A数组分成连续且不重合的M个子数组,使得第 i 个子数组的最小值与 B_i 相等。输出A数组的分法有多少种。其中B数组为递增数组。

思路:当正向分的时候会发现没有办法知道对于当前这个区间的右端点可以切割在哪里,因为B数组为递增数组,正向切割A数组的时候就有可能将下一个B也包括了进来,导致没有办法分出M个子数组,又或者不将下一个B包含进来就可能导致答案少了许多方案数。而反向去切割A数组:即先将A、B数组reverse。此时B数组为递减数组,那么当前切割的区间的右端点可以选择下一个B之前的所有位置。而相对应的,下一个B的左端点也可以选择为当前区间的最小值的位置到下一个B之间的所有位置。而实际上当前区间的右端点与下一个区间的左端点是同一个端点,因此选择当前区间右端点的方案数就是选择下一个区间的左端点方案数,所以不需要计算当前区间的左端点的选择有多少种选法,因为已经在上个区间中计算过了。(因为通了宵脑袋有点不清醒了,代码中L和R被我搞混成了右端点位置和左端点位置)。注意判断可能发生的各种情况:没有找到与B_i相等的A_i等。

第一个区间的左端点选择只有1,因为必须包括进B1前面的所有数,同时判断前面的数是否都大于B1。最后一个区间的右端点的选择也只有1,同时判断后面的数是否都大于Bm。

AC代码:

/*---------------------------------
 *File name: A.cpp
 *Creation date: 2020-07-05 03:38
 *Link: 
 *-------------------------------*/
#include
#include
#include
#include
#define pb push_back
#define LL long long
using namespace std;
const LL mod = 998244353;

int main(){
	int n, m;
	scanf("%d %d", &n, &m);
	vector a(n), b(m);
	for(int i = 0; i < n; ++i) scanf("%d", &a[i]);
	for(int j = 0; j < m; ++j) scanf("%d", &b[j]);
	reverse(a.begin(), a.end());
	reverse(b.begin(), b.end());
	LL ans = 1;
	int cur = 0;
	int r, l;
	l = 0, r = -1;
	while(l < n && a[l] > b[cur]) l++;
	if(l == n || a[l] != b[cur]) return printf("0\n"), 0;
	r = l;
	for(int i = 0; i < m - 1; ++i){
		if(i){
			r = l;
			while(l < n && a[l] > b[i]) l++;
			if(l == n || a[l] != b[i]) return printf("0\n"), 0;
			r = l;
		}
		while(l < n && a[l] >= b[i]) l++;
		if(l == n) return printf("0\n"), 0;
		ans = ans * (l - r);
		ans %= mod;
	}
	bool flag = 0;
	while(l != n) {
		if(a[l] == b[m - 1]) flag = 1;
		if(a[l++] < b[m - 1]) ans = 0;
	}
	if(!flag) ans = 0;
	printf("%lld\n", ans);
	return 0;
}

 

你可能感兴趣的:(Codeforces比赛题解)