[赛记] 多校A层冲刺NOIP2024模拟赛11 && 12
冒泡排序 100pts
比较显然的签到题 (好久没这么水过了);
考虑这个错的冒泡排序,手模一下即可发现这个 set
维护每个同余系的排名,最后按顺序输出即可;
对于正确性,相当于每次
时间复杂度:
点击查看代码
#include <iostream>
#include <cstdio>
#include <set>
using namespace std;
int n, k;
int a[5000005], ans[5000005];
multiset<int> s;
int main() {
freopen("bubble.in", "r", stdin);
freopen("bubble.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> k;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= k; i++) {
s.clear();
for (int j = i; j <= n; j += k) {
s.insert(a[j]);
}
for (int j = i; j <= n; j += k) {
ans[j] = *s.begin();
s.erase(s.begin());
}
}
for (int i = 1; i <= n; i++) cout << ans[i] << ' ';
return 0;
}
染色 4pts
给了1G原来是用在了bitset上;
转化题意:对于最终的序列,如1 1 1 1 1 2 2 3 3 3
,将其去重后变为 1 2 3
,则其合法当其为原序列
正确性很正确(但确实想不到);
那么设
证明考虑插板法;
那么我们的问题变为了求本质不同的子序列个数,但是子序列的任意相邻两项不相等;
发现原来的不太好转移,那么多开一维,设
那么这东西是 bitset
优化,复杂度
具体实现上需要注意一些细节,比如
有一些技巧:模
点击查看代码
#include <iostream>
#include <cstdio>
#include <bitset>
using namespace std;
const int mod = 2;
int t;
int n, m;
int a[500005];
bitset<200005> f[20005], sum, now;
int C(int n, int m) {
if ((n & m) == m) return 1;
else return 0;
}
int main() {
freopen("color.in", "r", stdin);
freopen("color.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> t;
while(t--) {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= m; i++) f[i].reset();
sum.reset();
now.reset();
for (int i = 1; i <= n; i++) {
now = sum ^ f[a[i]];
f[a[i]] = (now << 1);
f[a[i]][1] = 1;
sum = now ^ f[a[i]];
}
int ans = 0;
for (int i = 1; i <= n; i++) ans = (C(n - 1, i - 1) * sum[i] % mod + ans) % mod;
cout << ans;
}
return 0;
}
这场挂分挺多,算是给后天攒RP了吧
Alice 和璀璨花 100pts
树状数组维护最长上升子序列,时间复杂度
注意要先离散化,然后发现乘积项无法离散化,不过没有关系,直接将其赋值到比它小于等于的那个位置即可(因为求的是最长上升子序列所以没有影响,但如果这题求得是最长不下降可能就得用权值线段树了,时间复杂度
点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n;
long long a[1000005], b[1000005], c[5000005], f[1000005];
int cnt;
namespace BIT{
inline int lowbit(int x) {
return x & (-x);
}
long long tr[5000005];
void add(int pos, long long d) {
for (int i = pos; i <= cnt; i += lowbit(i)) tr[i] = max(tr[i], d);
}
long long ask(int pos) {
long long ans = 0;
for (int i = pos; i; i -= lowbit(i)) ans = max(ans, tr[i]);
return ans;
}
}
using namespace BIT;
long long ans;
int main() {
freopen("alice.in", "r", stdin);
freopen("alice.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
c[++cnt] = a[i];
}
for (int i = 1; i <= n; i++) {
cin >> b[i];
c[++cnt] = b[i];
}
c[++cnt] = 0;
c[++cnt] = -1;
sort(c + 1, c + 1 + cnt);
cnt = unique(c + 1, c + 1 + cnt) - c - 1;
for (int i = 1; i <= n; i++) {
f[i] = ask(lower_bound(c + 1, c + 1 + cnt, a[i]) - c - 1) + 1;
ans = max(ans, f[i]);
int pos = lower_bound(c + 1, c + 1 + cnt, a[i] * b[f[i]]) - c;
if (c[pos] != a[i] * b[f[i]]) pos--;
add(pos, f[i]);
}
cout << ans;
return 0;
}
David 与和谐号 8pts
呵呵,部分分暴搜,正解就换了种搜+剪了个枝;
好吧暴搜挂完了,36pts -> 8pts,调参少了一个;
正解是迭代加深搜索,并且剪了个枝;
发现我们的搜索树可能会很深,但答案很浅,所以可以迭代加深搜索(IDA*);
所谓IDA*,即每次固定一个搜索上界(设为
对于这个题,还有一个剪枝,就是当当前搜索到的深度的估价函数
所以当
时间复杂度:
注意在判断
点击查看代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
int t;
int n;
int a[55];
int ans;
void dfs(int x, int ls, int up, int sum) {
if (ans <= x - 1) return;
if (x - 1 > up) return;
bool vis = true;
for (int i = 1; i <= n; i++) {
if (a[i] != i) {
vis = false;
break;
}
}
if (vis) {
ans = min(ans, x - 1);
return;
}
if (x - 1 + sum > up) return;
for (int i = 2; i <= n; i++) {
if (i == ls) continue;
int now = sum + ((i < n) && (abs(a[i] - a[i + 1])) == 1) - ((i < n) && abs(a[1] - a[i + 1]) == 1);
reverse(a + 1, a + 1 + i);
dfs(x + 1, i, up, now);
reverse(a + 1, a + 1 + i);
}
}
int main() {
freopen("david.in", "r", stdin);
freopen("david.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> t;
while(t--) {
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
bool vis = true;
for (int i = 1; i <= n; i++) {
if (a[i] != i) {
vis = false;
break;
}
}
if (vis) {
cout << 0 << '\n';
continue;
}
int sum = 0;
for (int i = 2; i <= n; i++) {
if (abs(a[i] - a[i - 1]) >= 2) sum++;
}
ans = 0x3f3f3f3f;
int i = 1;
while(ans == 0x3f3f3f3f && i <= 2 * n + 2) {
dfs(1, 0, i, sum);
i++;
}
cout << ans << endl;
}
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步