随笔 - 11,  文章 - 6,  评论 - 0,  阅读 - 1030

A - Find Takahashi
题意:找到给定的数组中最大元素的下标

思路:水题(没有什么参考价值)

时间复杂度:O(n)

代码:

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



int main() {
	int n;
	cin >> n;
	
	int maxx = 0;
	int ans;
	for (int i = 1; i <= n; i ++ ) {
		int x;
		cin >> x;
		
		if(x > maxx) {
			maxx = x;
			ans = i; 
		}
	}	
	
	cout << ans << endl;
	
	
	
	return 0;
} 

B - ABC-DEF
题意:对于给定的A, B, C, D, E, F六个数,求出:(A×B×C)−(D×E×F) % 998244353

思路:对其应用取模规则

乘法取余: A * B % mod = ((A % mod) * (B % mod)) % mod
加法取余:(A + B) % mod = ((A % mod) + (B % mod)) % mod
减法取余:(A - B) % mod = (A % mod - B % mod + mod) % mod
整除取余:(A / B) % mod = (A % mod * B ^ (mod - 2) * mod) % mod

代码:

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

typedef long long LL;

const LL mod = 998244353;

LL a, b, c, d, e, f;

int main() {
	cin >> a >> b >> c >> d >> e >> f;
	
	LL temp = (((a % mod) * (b % mod) % mod) * (c % mod) % mod) % mod;
	
	LL temp1 = (((d % mod) * (e % mod) % mod) * (f % mod) % mod) % mod;
	
	
	LL ans = (temp % mod - temp1 % mod + mod) % mod;
	
	cout << ans << endl;
	
	
	
	return 0;
} 

C - Counting Squares

题意:在一个9 * 9的矩阵中,有多少个四个点都是‘#’组成的正方形

思路:模拟,通过枚举正方形的两个相邻的顶点,计算出另外的两个顶点,由于是在9 * 9的方格中,所以时间复杂度是满足的

时间复杂度:O(81 * 81)

代码:

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

const int N = 100;
char g[N][N];

bool solve(int x, int y) {
	if(x >= 1 && x <= 9 && y >=1 && y <= 9 && g[x][y] == '#') {
		return true;
	}
	
	return false;
}

int main() {
	for (int i = 1; i <= 9; i ++ ) {
		for (int j = 1; j <= 9; j ++ ) {
			cin >> g[i][j];
		}
	}	
	
	int ans = 0;
	
	for (int x1 = 1; x1 <= 9; x1 ++ ) {
		for (int y1 = 1; y1 <= 9; y1 ++ ) {
			for (int x2 = 1; x2 <= 9; x2 ++ ) {
				for (int y2 = 1; y2 <= 9; y2 ++ ) {
					if(x1 == x2 && y1 == y2) continue;
					
					if(g[x1][y1] == '.' || g[x2][y2] == '.') continue;
					
					int x3 = x2 - (y2 - y1);
					int y3 = y2 - (x1 - x2);
					int x4 = x1 - (y2 - y1);
					int y4 = y1 - (x1 - x2);
					
					if(solve(x3, y3) && solve(x4, y4)) {
						ans ++ ;
					}
				}
			}
		}
	}
	
	cout << ans / 4 << endl;
	
	
	
	return 0;
}

D - Yet Another Recursive Function

题意:定义函数f(0) = 1, 并且f(k) = f(k / 2) + f(k / 3) 此时的除法都是下取整,给定n,计算f(n)

思路:运行时间是两秒,n的范围是在long long中,,若是仅使用递归处理会发现运行超时,dp的话,无法用数组表示到1e18的范围,所以可以使用记忆化搜索,用unordered_map<LL, LL> mp记录已经计算过的值,使用时,直接在O(1)的时间内查找

时间复杂度:不太会看

代码:

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

typedef long  long LL;
unordered_map<LL, LL> mp;

LL f(LL n) {
	if(mp.count(n)) return mp[n];
	
	if(!n) return 1;
	
	return mp[n] = f(n / 2) + f(n / 3);
}

int main() {
	LL n;
	cin >> n;
	
	cout << f(n) << endl;

	
	
	return 0;
}

E - Sugoroku 4

题意:有n + 1个区域,分别是从0 - n,Takahashi想从0出发,最后到达n区域,每一次走多少通过转轮盘决定,轮盘的值是1 - M,当目前所在的区域i,与转到的路程j,有i + j > n的话,需要从n向0区域走(i + j - n)个距离
问:Takahashi在最多K次移动内到达n区域的总概率(% 998244353)

思路:dp解决,
集合:dp[i][j]表示在i次移动之内,正好到达j区域的总概率
属性:count(总和)

状态转移方程:
假设现在是i次移动内,达到j区域的总概率
对于本次之后的移动,有M种可能,可以分成两类:
1、当i + k <= M 的时候,dp[i + 1][j + k] += dp[i][j] / M (%998244353)
2、当i + k > M 的时候,dp[i + 1][2 * n - j - k] += dp[i][j] / M (%998244353)

在通过取余转换式,将两个式子转换,注意:
(A / B) % mod = (A % mod * B ^ (mod - 2) % mod) % mod

时间复杂度:O((N - 1) * M * K)

代码:

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

typedef long long LL;
const int mod = 998244353;
const int N = 1100;

LL f[N][N];

//快速幂 
LL qpow(LL a, LL b) {
	LL ans = 1;
	
	while (b) {
		if(b & 1) ans = ans * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return ans;
}

int main() {
	int n, m, cnt;
	cin >> n >> m >> cnt;
	
	LL M = qpow(m, mod - 2);

	f[0][0] = 1;
	
	for (int i = 0; i <= cnt; i ++ ) {
		for (int j = 0; j < n; j ++ ) {
			for (int k = 1; k <= m; k ++ ) {
				if(j + k <= n) {
					f[i + 1][j + k] = (f[i + 1][j + k] + f[i][j] * M) % mod;
				}
				else {
					f[i + 1][2 * n - j - k] = (f[i + 1][2 * n - j - k] + f[i][j] * M) % mod;
				}
			}
		}
	}
	
	LL ans = 0;
	
	for (int i = 0; i <= cnt; i ++ ) {
		ans = (ans + f[i][n]) % mod;
	}
	
	cout << ans << endl;
	
	
	return 0;
}

F - Erase Subarrays

题意:给定一个数组,你可以在数组中删除连续的区间,问:使得数组剩余的总和为x (x=1,2,…,M)分别需要删除多少个连续的区间

思路:动态规划dp,
集合:假设dp[i][j]表示考虑前i个数,当前保留数的总和是j的最小操作数
属性:Min

状态转移:我们同样来考虑最后一个数a[i]的取舍
1、当保留a[i]的时候,f[i][j] = min(f[i][j], f[i - 1][j - a[i]])
2、当不保留a[i](即进行删除操作)的时候, 我们需要枚举删除的连续一段是多少
dp[i][j] = min(dp[i][j], dp[k - 1][j] + 1) 其中 (1 <= k <= i)
这样的话时间复杂度是O(n ^ 3),数据范围是3000,3000 ^ 3 = 3 e 10,计算机一秒内最多计算1e7- 1e8左右所以会超时,这是我们可以使用一个数组pre[i][j] 来记录f[0][j], f[1][j], f[2][k],...,f[i][j]的最小值
此时的时间复杂度就是:O(n ^ 2),一秒内可以完成

代码:

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

#define inf 0x3f3f3f3f

const int N = 3100;
int f[N][N];
int pre[N][N];
int a[N];

int main() {
	int n, m;
	cin >> n >> m;
	
	for (int i = 1; i <= n; i ++ ) cin >> a[i];
	
	memset(f, inf, sizeof f);
	memset(pre, inf, sizeof pre);
	
	f[0][0] = 0;
	pre[0][0] = 0;
	
	for (int i = 1; i <= n; i ++ ) {
		for (int j = 0; j <= m; j ++ ) {
			if(j - a[i] >= 0) {
				f[i][j] = min(f[i][j], f[i - 1][j - a[i]]);
			}
			f[i][j] = min(f[i][j], pre[j][i - 1] + 1);
			pre[j][i] = min(f[i][j], pre[j][i - 1]);
		}
	} 
	
	for (int i = 1; i <= m; i ++ ) {
		if(f[n][i] == inf) f[n][i] = -1;
		
		printf("%d\n", f[n][i]);
	}
	
	
	return 0;
}

参考链接:https://zhuanlan.zhihu.com/p/578626304

posted on   知白-剑仙  阅读(95)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示