AtCoder Regular Contest 149

文章包含了AtCoderRegularContest149的六道编程题目,包括RepdigitNumber、TwoLISSum、AvoidPrimeSum等,涉及数学、排序和滑动窗口排序等算法问题,提供了详细的代码解决方案。
摘要由CSDN通过智能技术生成

AtCoder Regular Contest 149

A.   Repdigit   Number   ∘ \color{#007f00}\texttt{A. Repdigit Number}\color{red}~\circ A. Repdigit Number 

/*
    name: Repdigit Number
    id:   AT_arc149_a
    date: 2023/01/23
*/

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int n, m, a, b;

int main(){
	scanf("%d%d", &n, &m);
	ll p = 0;
	for(int i = 1; i <= n; ++ i){
		p = (p * 10 + 1);
		ll r = p % m;
		p %= m;
		for(int j = 1; j <= 9; ++ j){
			if(r * j % m == 0){
				a = i, b = j;
			}
		}
	}
	if(!a){
		puts("-1");
	} else {
		for(int i = 1; i <= a; ++ i){
			putchar(b + '0');
		}
		puts("");
	}
	return 0;
}

B.   Two   LIS   Sum   ∘ \color{#007f00}\texttt{B. Two LIS Sum}\color{red}~\circ B. Two LIS Sum 

/*
    name: Two LIS Sum
    id:   AT_arc149_b
    date: 2023/01/24
*/

#include <bits/stdc++.h>
using namespace std;

const int N = 3e5 + 10;
int n, a[N], b[N], st[N], top;

int main(){
	scanf("%d", &n);
	for(int i = 1; i <= n; ++ i){
		scanf("%d", &b[i]);
	}
	for(int i = 1; i <= n; ++ i){
		scanf("%d", &a[b[i]]);
	}
	st[++top] = a[1];
	for(int i = 2; i <= n; ++ i){
		if(st[top] < a[i]){
			st[++top] = a[i];
		} else {
			int k = lower_bound(st + 1, st + top + 1, a[i]) - st;
			st[k] = a[i];
		}
	}
	printf("%d\n", top + n);
	return 0;
}

C.   Avoid   Prime   Sum   ∘ \color{#00B0B0}\texttt{C. Avoid Prime Sum}\color{red}~\circ C. Avoid Prime Sum 

显然奇+奇为合数,偶+偶为合数,所以我们可以将上半部分填满奇数,下半部分填满偶数,然后只用考虑两部分交界的地方了。

如果 n n n 为偶数,那么可以直接枚举出来一个值域在 [ 2 n , n 2 ] [2n, n^2] [2n,n2] 的奇合数,然后把相加为这个数的二元组填到交界处。

如果 n n n 为奇数,那么边界会在中间有个拐弯,那么就在中间构造一个一下结构( 1 1 1 在正中心):

7
81
14

3 ∗ 3 3*3 33 没有 14 14 14,那就特判一下。

那么接着和上面一样填就好了。注意的是枚举奇合数从小往大可能会有问题(已经用了四个小的数),改成从大往小枚举就行了。

/*
    name: Avoid Prime Sum
    id:   AT_arc149_c
    date: 2023/01/24
*/

#include <bits/stdc++.h>
using namespace std;

const int N = 1010;
int n, vis[N*N], a[N][N];

bool isp(int k){
	for(int i = 2; i * i <= k; ++ i){
		if(k % i == 0){
			return false;
		}
	}
	return true;
}

int main(){
	scanf("%d", &n);
	if(n == 3){
		a[1][1] = 1;
		a[1][2] = 9;
		a[1][3] = 3;
		a[2][1] = 8;
		a[2][2] = 7;
		a[2][3] = 5;
		a[3][1] = 6;
		a[3][2] = 2;
		a[3][3] = 4;
	} else if(n & 1){
		int k = n / 2 + 1;
		a[k][k] = 1;
		a[k][k-1] = 8;
		a[k-1][k-1] = 7;
		a[k+1][k] = 14;
		vis[1] = vis[7] = vis[8] = vis[14] = 1;
		for(int i = n * n; i >= n + n; -- i){
			if((i & 1) && !isp(i)){
				int now = 2;
				for(int j = 1; j <= n; ++ j){
					int pos = j < k ? k-1 : k;
					if(a[pos][j]) continue;
					while(vis[now] || vis[i-now]) ++ now;
					if(now & 1){
						a[pos][j] = now;
						a[pos+1][j] = i - now;
					} else {
						a[pos][j] = i - now;
						a[pos+1][j] = now;
					}
					vis[now] = vis[i-now] = 1;
				}
				break;
			}
		}
		int tot1 = 1, tot2 = 2;
		for(int i = 1; i < k; ++ i){
			for(int j = 1; j <= n; ++ j){
				if(!a[i][j]){
					while(vis[tot1]){
						tot1 += 2;
					}
					a[i][j] = tot1;
					vis[tot1] = 1;
				}
			}
		}
		for(int i = k + 1; i <= n; ++ i){
			for(int j = 1; j <= n; ++ j){
				if(!a[i][j]){
					while(vis[tot2]){
						tot2 += 2;
					}
					a[i][j] = tot2;
					vis[tot2] = 1;
				}
			}
		}
	} else {
		for(int i = n + n; i <= n * n; ++ i){
			if((i & 1) && !isp(i)){
				for(int j = 1; j <= n; ++ j){
					if(j & 1){
						a[n/2][j] = j;
						a[n/2+1][j] = i - j;
					} else {
						a[n/2][j] = i - j;
						a[n/2+1][j] = j;
					}
					vis[j] = vis[i-j] = 1;
				}
				break;
			}
		}
		int tot1 = 1, tot2 = 2;
		for(int i = 1; i < n / 2; ++ i){
			for(int j = 1; j <= n; ++ j){
				if(!a[i][j]){
					while(vis[tot1]){
						tot1 += 2;
					}
					a[i][j] = tot1;
					vis[tot1] = 1;
				}
			}
		}
		for(int i = n / 2 + 2; i <= n; ++ i){
			for(int j = 1; j <= n; ++ j){
				if(!a[i][j]){
					while(vis[tot2]){
						tot2 += 2;
					}
					a[i][j] = tot2;
					vis[tot2] = 1;
				}
			}
		}
	}
	for(int i = 1; i <= n; ++ i){
		for(int j = 1; j <= n; ++ j){
			printf("%d ", a[i][j]);
		}
		puts("");
	}
	return 0;
}

D.   Simultaneous   Sugoroku   △ \color{#FF0000}\texttt{D. Simultaneous Sugoroku}\color{red}~\vartriangle D. Simultaneous Sugoroku 

考虑求解区间 [ 1 , 1 0 6 ] [1,10^6] [1,106] 的答案。

发现如果某个时刻,两个点所在位置互为相反数,那么两个点的答案也肯定互为相反数。所以我们可以在每次移动区间的时候只保留原点右侧或左侧的一个区间,易得这个区间是连续的。最后计算完 dfs 一下就能得到每个点的结果。

/*
    name: Simultaneous Sugoroku
    id:   AT_arc149_d
    date: 2023/01/24
*/
 
#include <bits/stdc++.h>
using namespace std;
 
const int N = 3e5 + 10, M = 1e6 + 10;
int n, m, x[N], d, ans[M], stop[M];
vector<int> g[M];
 
void dfs(int x, int v, int op){
	stop[x] = op;
	ans[x] = v;
	for(int i : g[x]){
		dfs(i, -v, op);
	}
}
 
int main(){
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; ++ i){
		scanf("%d", &x[i]);
	}
	int l = 1, r = 1000000, tag = 0;
	for(int i = 1; i <= m; ++ i){
		scanf("%d", &d);
		int mid;
		tag += d * (l + tag > 0 ? -1 : 1);
		mid = -tag;
		if(l <= mid && mid <= r){
			stop[mid] = i;
			if(mid - l > r - mid){
				for(int j = r; j > mid; -- j){
					g[mid*2-j].push_back(j);
				}
				r = mid - 1;
			} else {
				for(int j = l; j < mid; ++ j){
					g[mid*2-j].push_back(j);
				}
				l = mid + 1;
			}
		}
	}
	for(int i = 1; i <= 1000000; ++ i){
		if(stop[i]){
			dfs(i, 1, stop[i]);
		}
	}
	for(int i = l; i <= r; ++ i){
		ans[i] = i + tag;
		dfs(i, ans[i], 0);
	}
	for(int i = 1; i <= n; ++ i){
		if(stop[x[i]]){
			printf("Yes %d\n", stop[x[i]]);
		} else {
			printf("No %d\n", ans[x[i]]);
		}
	}
	return 0;
}

E.   Sliding   Window   Sort   △ \color{#FF0000}\texttt{E. Sliding Window Sort}\color{red}~\vartriangle E. Sliding Window Sort 

首先把问题转化为:把 a 0 , 1 , . . . , m − 2 a_{0,1,...,m-2} a0,1,...,m2 作为一个集合, a m − 1 , m , . . . , n a_{m-1,m,...,n} am1,m,...,n 作为队列,进行 k k k 次操作每次把队首放入集合,并取出集合内最小值放入队尾。

r = n − m + 1 r=n-m+1 r=nm+1,则若 k = r k=r k=r k k k 次操作后左边集合变为 { r + 1 , r + 2 , . . . , n } \{r+1,r+2,...,n\} {r+1,r+2,...,n},右边记为 ( x 1 , x 2 , . . . , x r ) (x_1,x_2,...,x_r) (x1,x2,...,xr)。如果左边集合不为 { r + 1 , r + 2 , . . . , n } \{r+1,r+2,...,n\} {r+1,r+2,...,n} 则无解。

接下来考虑 x x x 数组,如果存在 x i − 1 > x i x_{i-1}>x_i xi1>xi,那么这个 x i x_i xi 就只有一种可能位置(因为此时的集合的数必定都大于 x i − 1 x_{i-1} xi1,从而大于 x i x_i xi)。否则有 1 + ( m − 1 ) = m 1+(m-1)=m 1+(m1)=m 种可能位置。

因为集合是无序的,答案应该乘上 ( m − 1 ) ! (m-1)! (m1)!

如果 k > r k>r k>r,那么 [ r + 1 , r + 2 , . . . , k ] [r+1,r+2,...,k] [r+1,r+2,...,k] 的操作其实相当于对于右边的队列循环左移,可以转化为 k = r k=r k=r 的问题。

如果 k < r k<r k<r,那么在队列尾段的一段数是不用考虑的,也可以转化为 k = r k=r k=r 的问题。

/*
    name: Sliding Window Sort
    id:   AT_arc149_e
    date: 2023/01/24
*/

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 5e5 + 10;
const int P = 998244353;
int n, m, k, r, ans = 1, a[N], b[N];

int main(){
	scanf("%d%d%d", &n, &m, &k);
	r = n - m + 1;
	for(int i = 0; i < n; ++ i){
		scanf("%d", &a[i]);
	}
	rotate(a, a + k % n, a + n);
	for(int i = m - 1; i <= n; ++ i){
		b[i-(m-1)] = a[i];
	}
	if(k > r){
		rotate(b, b + (r - k % r) % r, b + r);//左移
		k = r;
	}
	for(int i = 1; i < m - 1; ++ i){//a不递增
		if(a[i] < a[i-1]){
			puts("0");
			return 0;
		}
	}
	for(int i = 0; i < k; ++ i){//b有贡献的部分不全小于a
		if(a[0] < b[r-1-i]){
			puts("0");
			return 0;
		}
	}
	for(int i = 1; i < m; ++ i){
		ans = (ll) ans * i % P;
	}
	for(int i = r-k, las = 0; i < r; ++ i){
		if(las < b[i]){
			las = b[i];
			ans = (ll) ans * m % P;
		}
	}
	printf("%d\n", ans);
	return 0;
}

F.   Rational   Number   System   − \color{#FF0000}\texttt{F. } \color{#965B2B}\texttt{Rational Number System}\color{grey}~- F. Rational Number System 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值