目录
B - Magical Subsequence(暴力、贪心)
思路
因为 A [ i ] + A [ j ] = s u m A[i] + A[j] = sum A[i]+A[j]=sum不会超过200,因此直接枚举 s u m sum sum,找到每个 s u m sum sum对应的 b b b序列长度,再取最长的 b b b序列长度。
对于每个 s u m sum sum,用 p o s [ k ] pos[k] pos[k]表示数字 k k k在数组 A A A中最后出现的位置。遍历 A A A数组,设当前遍历到第 i i i个,若 s u m − A [ i ] sum - A[i] sum−A[i]恰好在前面出现过,且 p o s [ s u m − A [ i ] ] pos[sum - A[i]] pos[sum−A[i]]比已找好的 b b b序列最后一个元素还要大,即 p o s [ s u m − A [ i ] ] pos[sum - A[i]] pos[sum−A[i]]还未被计入 b b b数组中,则可将 i i i也计入 b b b序列中。
其实这就是一个区间覆盖的经典贪心问题,等价于有很多的区间(配对上的位置是区间端点),区间之间会相互覆盖或相互包含,求最多的不相交区间数量,先将区间按照右端点排序,从左到右遍历区间,如果交到之前的区间就不选,否则就选。
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int a[N], pos[N], n;
int main()
{
scanf("%d", &n);
int mi = 1e9, mx = 0;
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]), mi = min(mi, a[i]), mx = max(mx, a[i]);
mi *= 2, mx *= 2;
int ans = 0;
for(int i = mx; i >= mi; i --)
{
memset(pos, 0, sizeof pos);
int last = 0, cnt = 0;
for(int j = 1; j <= n; j ++)
{
if(i <= a[j]) continue;
if(pos[i - a[j]] > last)
{
last = j;
cnt += 2;
}
else pos[a[j]] = j;
}
ans = max(ans, cnt);
}
printf("%d\n", ans);
}
D - Math master(二进制枚举、细节)
思路
不难想到可以二进制枚举分子删掉了哪些数位,令删掉这些数位之后得到的新分子为 n p np np,则新分母 n q = n p ∗ q / p nq = np * q / p nq=np∗q/p。所以只需要看旧分母在删掉新分子相对旧分子删掉的那些数字可否等于 n q nq nq即可。
记录新分子相比于旧分子删掉的每个数字 i i i的个数 p s u b [ i ] psub[i] psub[i], 再记录 n q nq nq相比于旧分母删掉的每个数字 i i i的个数 q s u b [ i ] qsub[i] qsub[i],首先对于 1 1 1~ 9 9 9每个数字 i i i,均要有 p s u b [ i ] = q s u b [ i ] psub[i] = qsub[i] psub[i]=qsub[i],对于数字0,注意有前导0的问题,就是如果 q s u b [ i ] > p s u b [ i ] qsub[i] > psub[i] qsub[i]>psub[i],说明 n q nq nq现在含有的0数量太少了,和原来差距太大,因此含有前导0,因此先将 n q nq nq前面补足 q s u b [ i ] − p s u b [ i ] qsub[i] - psub[i] qsub[i]−psub[i]个0。
最后将旧分母和 n q nq nq从前到后一一比较,如果某 i i i位不同,则旧分母应该将第 i i i位的数 d i g i t [ i ] digit[i]

本文详细解析了多项算法竞赛题目,包括暴力、贪心、二进制枚举、期望及状态压缩动态规划等多种策略的应用。通过对具体问题的深入探讨,为读者提供了清晰的解题思路与实现代码。
最低0.47元/天 解锁文章
5122

被折叠的 条评论
为什么被折叠?



