2020ACM俱乐部后备营个人训练赛第四场

问题 A: Domino

第一题考察的斐波那契数列,当然也可以当作一道简单的找规律的题目,
递推公式为f[i] = (f[i - 1] + f[i - 2]) % mod

下面附上代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1010;
const int mod = 1e9 + 7;

int f[N];
int main() {
	int n; cin >> n;
	f[1] = 1;
	f[2] = 2;
	
	for (int i = 3; i <= n; i ++ ) {
		f[i] = (f[i - 1] + f[i -  2]) % mod;
	}
	
	cout << f[n] << endl;
	
	return 0;
} 

问题 B: Block

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 2010;

typedef long long ll;

ll s[N][N];

int main() {
	int n, m; scanf("%d%d", &n, &m);
	
	for (int i = 1; i <= n; i ++ ) 
		for (int j = 1; j <= m; j ++ ) 
			scanf("%1lld", &s[i][j]);
			
	for (int i = 1; i <= 2 * n; i ++ )
		for (int j = 1; j <= 2 * m; j ++ ) 
			s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
	
	ll ans = 9e9;
	for (int k = 2; k <= min(n, m); k ++ ) {
		ll sum = 0;
		for (int i = k; i <= 2 * n; i += k) 
			for (int j = k; j <= 2 * m; j += k) {
				ll c = s[i][j] - s[i - k][j] - s[i][j - k] + s[i - k][j - k];
				sum += min(1ll * k * k - c, c);
			}
		ans = min(ans, sum);
	}
	
	cout << ans << endl;
	return 0;
}

问题 E: 夏令营小旗手

简单的模拟一下

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 10010;

int n, x;
int cnt[N];

int main() {
	cin >> n >> x;
	
	cnt[x] ++;
	for (int i = 2; i <= n; i ++ ) {
		int t = (x * 37 + 33031) % n + 1;
		cnt[t] ++;
		x = t;
		//cout << t << endl;
	}
	
	
	cout << max_element(cnt, cnt + n + 1) - cnt << endl;
	
	return 0;	
}

问题 G: 分数计数

这一题是一道模拟题,需要做的仅是将题目中给的条件实现。
没什么好说的,就介绍一个algorithm头文件下的一个函数吧,max_element();
详细解释连接:https://blog.csdn.net/qq_37978559/article/details/109782755

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 110;

int n, x;
int a[N];//计数数组 

int main() {
	cin >> n >> x;
	
	a[x] = 1;
	int cnt = 1; 
	//注意:x的作用为题目中的x(i-1) 
	for (int i = 1; i < n; i ++ ) {
		int t = (x * 3703 + 1047) % n + 1;//公式 
		if (t == x && cnt < 3) cnt ++;//如果连续且不超过3词 
		else if (t == x && cnt >= 3) cnt = 3;//连续大于三次,只记入3 
		else cnt = 1;//如果不连续,计入1 
		a[t] += cnt;//加到计数数组中 
		x = t;//x记录当前数 
	}
	//调用algorithm头文件的函数max_element(),找到最大值 
	cout << *max_element(a, a + 1 + n) << endl;
	
	return 0;
} 

问题 H: 连续数的和

这一题连续的数可以用很多种方法来做,可以使用前列和来做,可以模拟,也可以使用滑动窗口,也可以用双指针来做。
这里介绍一下滑动窗口的方法来做。
首先简单介绍一下滑动窗口是什么,就是保证我们处理数据的时候,只针对固定长度的数据。比如题目这里的,处理一个长度为k的连续数字的和。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <map>

using namespace std;

const int N = 70010;

map<int, int> h;
void init() {//预处理一下给定数据的所有平方数
	for (int i = 1; i <= 70000; i ++ ) 
		h[i * i] = 1;
}
int main() {
	int n, k; cin >> n >> k;
	init();
	
	int sum = 0, cnt = 0;
	for (int i = 1; i <= n; i ++ ) {
		sum += i;
		if (i > k) sum -= i - k;//如果当前区间左端点大于i,我们每次减去k长度之前的数,就得到了i-k+1~i的区间和	
		if (i >= k && h.count(sum)) cnt ++;//count函数,查找当前sum是否为平方数
	}
	
	cout << cnt << endl;
	
	return 0;
}

但是小伙伴这里告诉我了一种更高明的滑动窗口的做法,先求出1~k的和,然后每次向后滑动一位的时候,只需要给1~k的和,加上k即可。
例如,k=3时,先求出1 + 2 + 3 = 6,这是1到3,区间长度为3的区间和,如果我们想要求2~4的和,只需要给6 + 3 即可。
(1 + 1) + (2 + 1)+ (3 + 1) = 1 + 2 + 3 + 3 = sum + k
下面是代码:

#include <iostream>
#include <cmath>

using namespace std;

int n, k, cnt, a;
int main()
{
   cin >> n >> k;
	for (int i = 1; i <= k; i ++)
       a += i;
    for(int i = 1; i <= n - k; i ++){
       if (floor(sqrt(a)) == sqrt(a))   cnt += 1;
   }
    cout << cnt << endl;
    return 0; 
}

问题 K: 求回文数

这一题让求字符串反转,没什么好说的,这里介绍一个函数:to_string();
可以将其他类型的数据转化为字符串string类型;
再介绍一个函数,是algorithm头文件里的,reverse可以将字符串翻转;

下面是代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

int main() {
	int n; cin >> n;
	int cnt = 0;
	for (int i = 1; i <= n; i ++ ) {
		string s = to_string(i);
		string str = s;
		reverse(s.begin(), s.end());
		
		if (s == str) cnt ++;
	}
	
	cout << cnt << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值