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;
}