文章目录
- AcWing 3485. 最大异或和 (美团2021,笔试题)
- AcWing 3493. 最大的和(贝壳找房2021,笔试题)
- AcWing 3499. 序列最大收益 (中兴2021,笔试题)
- AcWing 3502. 不同路径数(贝壳找房2021,笔试题)
- AcWing 3510. 最长公共子序列(上海交通大学考研机试题)
- AcWing 3489. 星期几(上海交通大学考研机试题)
- AcWing 3481. 阶乘的和 (上海交通大学考研机试题)
- AcWing 3516. 最大面积 (今日头条2021,笔试题)
- AcWing 3404. 谁是你的潜在朋友 (北京大学考研机试题)
- AcWing 3483. 2的幂次方 (上海交通大学考研机试题)
- AcWing 3333. K-优字符串 (Google Kickstart2021 Round A Problem A)
AcWing 3485. 最大异或和 (美团2021,笔试题)
原题链接:AcWing 3485. 最大异或和 输入样例:
3 2
1 2 4
输出样例:
6
题解
为了快速算出一段区间的异或值,所以需要使用前缀和(异或),转化成求两个前缀异或的最大值。 在转换成之后,又需要保证两个前缀之间的间距不超过m,所以需要开一个cnt数组,记录当前节点是否有值,删除时需要对其-1,insert时需要+1。
代码
// https://www.acwing.com/activity/content/code/content/1261349/
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 32 * 1e5 + 4;
int s[N], x;
int trie[N][2], idx;
int cnt[N]; // 删除需要的地方,当时没想到
void insert(int x, int v) {
int p = 0;
for (int i = 30; ~i; i--) {
int u = x >> i & 1;
if (!trie[p][u])
trie[p][u] = ++idx;
p = trie[p][u];
cnt[p] += v;
}
}
int query(int x) {
int p = 0, res = 0;
for (int i = 30; ~i; i--) {
int u = x >> i & 1;
if (cnt[trie[p][!u]])
p = trie[p][!u], res = res * 2 + 1;
else
p = trie[p][u], res = res * 2;
}
return res;
}
int main() {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", &x);
s[i] = s[i - 1] ^ x;
}
insert(s[0], 1);
int res = 0;
for (int i = 1; i <= n; i++) {
if (i > m)
insert(s[i - m - 1], -1);
res = max(res, query(s[i]));
insert(s[i], 1);
}
cout << res << endl;
return 0;
}
AcWing 3493. 最大的和(贝壳找房2021,笔试题)
原题链接:AcWing 3493. 最大的和 输入样例1:
3 1
2 5 4
0 0 1
输出样例1:
9
输入样例2:
4 3
10 5 4 7
0 1 1 0
输出样例2:
19
题解
- 先把所有的为1的状态求和 2. 再次遍历,如果这个状态为0,先加上这个位置的值 3. 如果此时下标i与i-m这段长度为i-(i-m)+1长度超过了m,需要去掉i-m的影响(出队) 4. 更新最大值
代码
// https://www.acwing.com/activity/content/code/content/1223424/
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100000 + 5;
int arr[N];
bool st[N];
int main(){
int n, m;
long long res = 0, sum = 0;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ ){
scanf("%d", &arr[i]);
}
for (int i = 1; i <= n; i ++ ){
scanf("%d", &st[i]);
if (st[i]) sum += arr[i];
}
// cout << sum << endl;
for (int i = 1; i <= n; i ++ ){
if (!st[i]) sum += arr[i];
if (i >= m && !st[i - m]) sum -= arr[i - m];
res = max(res, sum);
}
cout << res << endl;
return 0;
}
AcWing 3499. 序列最大收益 (中兴2021,笔试题)
原题链接:3499. 序列最大收益 输入样例:
4 1 3
1 4 2
0 3 0 1
3 0 0 0
0 0 0 0
1 0 0 0
输出样例:
3
样例解释 初始序列收益和为 w1,4+w4,2=1+0=1。
删除中间的 4 后,序列 1,2 的收益和为 w1,2=3。
题解
代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 210;
int a[N], arr[N][N], f[N][N];
int n, k, m;
int main()
{
cin >> n >> k >> m;
for (int i = 1; i <= m; i ++ )
cin >> a[i];
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
cin >> arr[i][j];
// f[i][j],以i结尾,删除了k个数
// 不同点在于前i-1个点,想要从那个点转移过来,需要删除i-u-1个点
// f[1][0] = a[0];
for (int i = 1; i <= m; i ++ ){
for (int j = 0; j <= k; j ++ ){
for(int u = i - 1; u; u--){
if (j>=i-u-1)
f[i][j] = max(f[i][j], f[u][j-(i-u-1)]+arr[a[u]][a[i]]);
}
}
}
int res = 0;
for(int i = 0; i <= k; i++)
res = max(res, f[m][i]);
cout << res;
return 0;
}
AcWing 3502. 不同路径数(贝壳找房2021,笔试题)
原题链接:AcWing 3502. 不同路径数 输入样例:
3 3 2
1 1 1
1 1 1
2 1 1
输出样例:
5
样例解释 一共有 5 种可能的 3 位数:
111 112 121 211 212
题解
(暴力枚举) O(n2) 暴力枚举,dfs 借助set判重,每次dfs将当前数位加到string的最后一位 当dfs层数达到k层时,就将数据插入到set中
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_set>
using namespace std;
const int N = 10;
int n, m, k;
int w[N][N];
unordered_set<int> S;
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
void dfs(int x, int y, int u, int num)
{
if (u > k) S.insert(num);
else
{
for (int i = 0; i < 4; i ++ )
{
int a = x + dx[i], b = y + dy[i];
if (a >= 0 && a < n && b >= 0 && b < m)
dfs(a, b, u + 1, num * 10 + w[a][b]);
}
}
}
int main()
{
scanf("%d%d%d", &n, &m, &k);
for (int i = 0; i < n; i ++ )
for (int j = 0; j < m; j ++ )
scanf("%d", &w[i][j]);
for (int i = 0; i < n; i ++ )
for (int j = 0; j < m; j ++ )
dfs(i, j, 1, w[i][j]);
printf("%d\n", S.size());
return 0;
}
AcWing 3510. 最长公共子序列(上海交通大学考研机试题)
原题链接 AcWing 3510. 最长公共子序列
题解
因为a数组没有重复数字,所以b中的数对应a的时侯是一一对应的; 那么b数组就转换成了一系列的下标; 因为子序列是上升的; 所以公共子序列就对应了那串下标的一个子序列,该子序列是上升的; 所以最长公共子序列就转换成了最长上升子序列;
代码
// https://www.acwing.com/activity/content/code/content/1260054/
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 1000005;
int a1[N], a2[N];
int f[N], len;
int main() {
int n, a;
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &a), a1[a] = i;
for (int i = 1; i <= n; i++) scanf("%d", &a), a2[i] = a1[a];
for (int i = 1; i <= n; i++) {
// printf("%d ", a2[i]);
if (!a2[i]) continue;
if (!len || f[len - 1] < a2[i]) f[len++] = a2[i];
else {
int j = lower_bound(f, f + len, a2[i]) - f;
f[j] = a2[i];
}
}
cout << len << endl;
return 0;
}
AcWing 3489. 星期几(上海交通大学考研机试题)
原题链接 输入样例:
9 October 2001
14 October 2001
输出样例:
Tuesday
Sunday
题解
模拟题,没什么题解
代码
//https://www.acwing.com/activity/content/code/content/1260059/
#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_map>
using namespace std;
int month[15]= {0, 31, 28, 31, 30, 31, 30, 31 ,31,30,31,30,31};
string months[15]={"0", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
string days[10] = {"Sunday","Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday",""};
int main()
{
int d, y;
string M;
int m;
while(cin >> d >> M >> y){
int res = d;
for (int i = 1; i <= 14; i ++) {if (months[i] == M) {m = i; break;}}
for (int i = 1; i < m ; i ++ ) res += month[i];
if (y % 4 == 0 && y % 100 || y % 400 == 0) {
if (m > 2) res++;
}
for (int i = 1; i < y; i ++ ){
if (i % 4 == 0 && i % 100 || i % 400 == 0) res += 366;
else res += 365;
}
cout << days[res % 7] << endl;
}
return 0;
}
AcWing 3481. 阶乘的和 (上海交通大学考研机试题)
原题链接
输入样例:
9
-1
输出样例:
YES
题解
因为数据不大,直接先计算出<1e6的阶乘,然后枚举所有的选择可能
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_set>
using namespace std;
int f[10];
unordered_set<int> S;
int main()
{
for (int i = 0; i < 10; i ++ )
{
f[i] = 1;
for (int j = i; j; j -- )
f[i] *= j;
}
for (int i = 1; i < 1 << 10; i ++ )
{
int s = 0;
for (int j = 0; j < 10; j ++ )
if (i >> j & 1)
s += f[j];
S.insert(s);
}
int n;
while (cin >> n, n >= 0)
if (S.count(n))
puts("YES");
else
puts("NO");
return 0;
}
AcWing 3516. 最大面积 (今日头条2021,笔试题)
原题链接
题解
代码
// https://www.acwing.com/activity/content/code/content/1259248/
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 3005;
bool arr[N][N];
int f[N][N];
int l[N], r[N], u[N], d[N];
int width[N];
int s[N], tt;
int calc(int h[], int n) {
s[n + 1] = tt = 0; //边界处理
int res = 0;
for (int i = 1; i <= n + 1; i++) {
int w = 0;
while (h[i] < s[tt]) {
w += width[tt];
res = max(res, w * s[tt]);
tt--;
}
s[++tt] = h[i], width[tt] = w + 1;
}
return res;
}
void init(int n, int m) {
memset(f, 0, sizeof f);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
f[i][j] = (f[i - 1][j] + arr[i][j]) * arr[i][j];
}
u[i] = max(u[i - 1], calc(f[i], m));
}
memset(f, 0, sizeof f);
for (int i = n; i; i--) {
for (int j = 1; j <= m; j++) {
f[i][j] = (f[i + 1][j] + arr[i][j]) * arr[i][j];
}
d[i] = max(d[i + 1], calc(f[i], m));
}
memset(f, 0, sizeof f);
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
f[i][j] = (f[i - 1][j] + arr[j][i]) * arr[j][i];
}
l[i] = max(l[i - 1], calc(f[i], n));
}
memset(f, 0, sizeof f);
for (int i = m; i; i--) {
for (int j = 1; j <= n; j++) {
f[i][j] = (f[i + 1][j] + arr[j][i]) * arr[j][i];
}
r[i] = max(r[i + 1], calc(f[i], n));
}
}
int main() {
int n, m;
scanf("%d%d", &n, &m);
getchar();
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
arr[i][j] = getchar() - '0';
// printf("%d", arr[i][j]);
}
// puts("");
getchar();
}
init(n, m);
int q, x, y;
scanf("%d", &q);
while (q--) {
scanf("%d%d", &x, &y);
x++, y++;
printf("%d\n", max(max(l[y - 1], r[y + 1]), max(u[x - 1], d[x + 1])));
}
return 0;
}
AcWing 3404. 谁是你的潜在朋友 (北京大学考研机试题)
原题链接 输入样例:
4 5
2
3
2
1
输出样例:
1
BeiJu
1
BeiJu
题解
标记一个数出现多少次即可
代码
// https://www.acwing.com/activity/content/code/content/1260595/
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 210;
int n, m;
int p[N];
int s[N];
int main()
{
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i ++ )
{
scanf("%d", &p[i]);
s[p[i]] ++ ;
}
for (int i = 0; i < n; i ++ )
if (s[p[i]] == 1) puts("BeiJu");
else printf("%d\n", s[p[i]] - 1);
return 0;
}
AcWing 3483. 2的幂次方 (上海交通大学考研机试题)
原题链接 输入样例:
1315
输出样例:
2(2(2+2(0))+2)+2(2(2+2(0)))+2(2(2)+2(0))+2+2(0)
递归
注意判断当指数为0和1时,就不继续递归下去
代码
// https://www.acwing.com/activity/content/code/content/1261347/
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
string dfs(int n)
{
string res;
for (int i = 14; i >= 0; i -- )
if (n >> i & 1)
{
if (res.size()) res += '+';
if (!i) res += "2(0)";
else if (i == 1) res += "2";
else res += "2(" + dfs(i) + ")";
}
return res;
}
int main()
{
int n;
while (cin >> n)
cout << dfs(n) << endl;
return 0;
}
AcWing 3333. K-优字符串 (Google Kickstart2021 Round A Problem A)
原题链接 输入样例:
2
5 1
ABCAA
4 2
ABAA
输出样例:
Case #1: 0
Case #2: 1
样例解释 对于测试数据 1,给定字符串的优良分数刚好为 1,所以不需要任何操作。
对于测试数据 2,将索引 1 处的字符改为 B 即可。
题解
把满足条件的找出来,然后减去即可
代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 200010;
int n, k;
char str[N];
int main()
{
int T;
scanf("%d", &T);
for (int C = 1; C <= T; C ++ )
{
printf("Case #%d: ", C);
scanf("%d%d%s", &n, &k, str);
int cnt = 0;
for (int i = 0, j = n - 1; i < j; i ++, j -- )
if (str[i] != str[j])
cnt ++ ;
printf("%d\n", abs(cnt - k));
}
return 0;
}
串的优良分数刚好为 1,所以不需要任何操作。
对于测试数据 2,将索引 1 处的字符改为 B 即可。
题解
把满足条件的找出来,然后减去即可
代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 200010;
int n, k;
char str[N];
int main()
{
int T;
scanf("%d", &T);
for (int C = 1; C <= T; C ++ )
{
printf("Case #%d: ", C);
scanf("%d%d%s", &n, &k, str);
int cnt = 0;
for (int i = 0, j = n - 1; i < j; i ++, j -- )
if (str[i] != str[j])
cnt ++ ;
printf("%d\n", abs(cnt - k));
}
return 0;
}