SMU Summer 2024 Contest Round 4
2024.7.16 9:00————11:00
过题数3/7
补题数6/7
- Made Up
- H and V
- Moving Piece
- Sum of Divisors
- Red and Green Apples
- Rem of Sum is Num
- Keep Connect
A - Made Up
题解:
给定三个数组a,b,c,各自包含n个数字,求有多少组的
a[i]=b[c[j]]
因为给定的数组中数字大小范围是从1到n,将b中数组重新赋值一次后,相同的数字个数相乘即可。
代码:
#include<bits/stdc++.h>using namespace std;
#define int long longsigned main() {int n;cin >> n;int a[100005],b[100005],c[100005];int bb[100005];int aa[100005];for (int i = 1; i <= n; i++) {aa[i] = 0;bb[i] = 0;}for (int i = 1; i <= n; i++) {cin >> a[i];aa[a[i]]++;}for (int i = 1; i <= n; i++) {cin >> b[i];}for (int i = 1; i <= n; i++) {cin >> c[i];bb[b[c[i]]]++;}int sum = 0;for (int i = 1; i <= n; i++) {sum+=(bb[i] * aa[i]);}cout << sum;return 0;
}
B - H and V
当时写了个巨长的二进制枚举,四重循环中间套循环套字符数组,后来去看了看别人写的,还挺简洁的。
题解:
h行w列,白色是’.',黑色是‘#’,每次可选取任意行或列的方块变成红色,要求最后剩下k个黑块有多少种方案。
数据给的比较小,六以内,直接二进制枚举遍历,不过要注意方法,不然真的非常费时。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int h,w,k;
char ys[10][10];
int a[10][10];signed main() {cin >> h >> w >> k;for (int i = 0; i < h; i++) {for (int j = 0; j < w; j++) {cin >> ys[i][j];}}int ans = 0;for (int i = 0; i <= (1 << h)-1; i++) {for (int a = 0; a <= (1 << w)-1; a++) {int res = 0;for (int j = 0; j < h; j++) {for (int b = 0; b < w; b++) {if((a>>b&1) && ((i>>j&1)) && ys[j][b] == '#') {res++;}}}if(res == k)ans++;}}cout << ans;return 0;
}
//虽然过了但是巨长巨乱的代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int h,w,k;
char ys[10][10];
int a[10][10];signed main() {cin >> h >> w >> k;for (int i = 1; i <= h; i++) {for (int j = 1; j <= w; j++) {cin >> ys[i][j];}}int ans = 0;for (int i = 0; i <= (1 << h)-1; i++) {char c[10][10];for (int f = 1; f <= h; f++) {for (int s = 1; s <= w; s++) {c[f][s] = ys[f][s];}}for (int j = 0; j < h; j++) {if(i >> j & 1) {for (int p = 1; p <= w; p++) {c[j+1][p] = '!';}}}for (int a = 0; a <= (1 << w)-1; a++) {char cc[h][w];for (int f = 1; f <= h; f++) {for (int s = 1; s <= w; s++) {cc[f][s] = c[f][s];}}for (int b = 0; b < w; b++) {if(a >> b & 1) {for (int q = 1; q <= h; q++) {cc[q][b+1] = '!';}}}int res = 0;for (int l = 1; l <= h; l++) {for (int r = 1; r <= w; r++) {if(cc[l][r] == '#')res++;}}if(res == k)ans++;}}cout << ans;return 0;
}
C - Moving Piece
这题挺…怎么说呢
题解:
英文题面,可以移动1到k内任意步数,每次移动必须到第p[i]位置,并会获得c[p[i]]价值,最多可以获得多少价值。
思路比较清晰,用到前缀和思想,找出最大值,如果陷入循环,因为K比较大,可以直接相乘得出。
有八个样例点考察在当K比较大时,最后一组循环也应该要找到最大的一个位置停住,而不是一直找下去找完这个循环,见注释。
代码:
#include<bits/stdc++.h>using namespace std;
#define int long long
int n,k;
int p[5005];
int c[5005];
int res[5005];
int st[5005];signed main() {cin >> n >> k;for (int i = 1; i <= n; i++) cin >> p[i];for (int i = 1; i <= n; i++) cin >> c[i];int ma = -1e10;//注意c数组的范围for (int i = 1; i <= n; i++) {res[i] = -1e10;int j = i;int t = 0;int sum = 0;memset(st,0,sizeof st);//memset只可全部赋值为-1或0while (1) {//除非遇到中止循环的情况j = p[j];if(st[j] == 1) {//这个已经走过了,说明开始循环int z = p[i];int lsum = 0;int lt = 0;while (z != j) {sum -= c[z];lsum += c[z];z = p[z];t--;lt++;}//这一大串都是在判断循环的部分,因为前面俩三个可能没进入循环,但是!这个判断是没有样例点的呵呵int lr = res[i];k = k-lt;int ls = k/t;if(k % t == 0)ls--;//留出最后一次循环res[i] =ls*sum + lsum;int laa = -1e10;int aaa = 0;for (int s = 1; s <= (k%t ? k % t: t); s++){j = p[j];aaa += c[j];laa = max(laa,aaa);//就是这一段,有八个样例点,最后一次循环不用非走到最后一步}res[i] = res[i] + laa;res[i] = max(res[i],lr);//sum是负数的情况,多次循环会越来越小break;}sum+=c[j];st[j] = 1;t++;if(res[i] < sum) res[i] = sum;//其实是前缀和思想,sum不一定越来越大但我只要最大的那一个if(t == k) break;//步数走完且未循环}ma = max(ma,res[i]);}cout << ma;return 0;
}
D - Sum of Divisors
代码简单难在思考难度
题解:
求k从1到n的(k*k的因数的和)的和。
n范围最大到10的7次方,直接暴力会爆。所以考虑1到n会是谁的因数,然后这些数字相加即可,最后全部相加。
代码:
#include<bits/stdc++.h>using namespace std;
#define int long long signed main() {int n;cin >> n;int ans = 0;for (int i = 1; i <= n; i++) {int res = n/i;int ls = res*i;ans += (i+ls)*res/2;//首项+尾项 * 项 / 2; }cout << ans << endl;return 0;
}
E - Red and Green Apples
题解:
你需要x个红苹果和y个绿苹果,有c个可以染色的苹果。你需要尽可能拿到最大重量和。
将最大的x个红苹果和最大的y个绿苹果都输入multiset,在给进去x+y(如果有的话)个可染色苹果,然后排序输出最大的x+y个和即可。
代码:
#include<bits/stdc++.h>using namespace std;
#define int long long
int x,y,a,b,c;
int p[100005];
int q[100005];
int r[100005];signed main() {cin >> x >> y >> a >> b >> c;for (int i = 1; i <= a; i++)cin >> p[i];for (int i = 1; i <= b; i++)cin >> q[i];for (int i = 1; i <= c; i++)cin >> r[i];sort(r+1,r+c+1,greater<>());sort(p+1,p+a+1,greater<>());sort(q+1,q+b+1,greater<>());multiset<int>re;re.clear();for (int i = 1; i <= x; i++) {re.insert(p[i]);}for (int i = 1; i <= y; i++)re.insert(q[i]);for (int i = 1; i <= min(x+y,c); i++)re.insert(r[i]);//万一不够也得全部输入int ans = 0;int js = 0;for (auto aaa : re) {js++;if(js > re.size()-x-y) {ans += aaa;}//哎呀实在写不出递减set当时,只能这么输出了}cout << ans;return 0;
}
F - Rem of Sum is Num
题解:
前缀同余
代码: