难度顺序:
1. D A
2. E C F
3. G H B
D:思维 A :dfs递归
E:记忆化搜索 C:BFS删点 F:DP
G:思维 H:DP B:思维 + 二分
A
很明显发现答案就是一棵二叉树的中序遍历
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int t[N << 1];
void build(int k, int val)
{
t[k] = val;
if (val == 20)
return;
build(k << 1, val + 1);
build(k << 1 | 1, val + 1);
}
int n;
void dfs(int k)
{
if (!n)
return;
if (t[k << 1])
dfs(k << 1);
if (n)
{
cout << t[k] << ' ';
n--;
}
if (t[k << 1 | 1])
dfs(k << 1 | 1);
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n;
build(1, 1);
dfs(1);
}
B
一轮可以删除的位置是:1,2,3,5,7,11…
我们必定能在有限轮内删除完,我们对每一轮进行模拟,即可得到每一轮删除的数,利用vector直接记录。
操作一:求第k个数在第几次被删除
操作二:求第k次删除的是哪个数
都可以直接枚举轮数,再利用二分解决
#include <bits/stdc++.h>
using namespace std;
vector<int> vis((int)1e6 + 5);
void ES()
{
for (int i = 2; i <= (int)1e6; ++i)
{
if (!vis[i])
{
for (int j = i << 1; j <= (int)1e6; j += i)
vis[j] = 1;
}
}
}
vector<int> del((int)1e6);
vector<vector<int>> mark(100);
void Del()
{
iota(del.begin(), del.end(), 1);
int cnt = 0;
int sum = (int)1e6;
while (sum)
{
++cnt;
int temp = 0;
for (int i = 1; i <= sum; ++i)
{
if (!vis[i])
mark[cnt].emplace_back(del[i - 1]);
else
del[temp++] = del[i - 1];
}
mark[cnt].emplace_back((int)1e6 + 5);
sum = temp;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
ES();
Del();
while (t--)
{
int op, n, k;
cin >> op >> n >> k;
if (op == 1)
{
int ans = 0;
for (int i = 1; i <= 80; ++i)
{
int pos;
if (*lower_bound(mark[i].begin(), mark[i].end(), k) == k)
{
pos = lower_bound(mark[i].begin(), mark[i].end(), k) - mark[i].begin() + 1;
ans += pos;
break;
}
else
{
pos = upper_bound(mark[i].begin(), mark[i].end(), n) - mark[i].begin();
ans += pos;
}
}
cout << ans << '\n';
}
else
{
for (int i = 1; i <= 80; ++i)
{
int pos;
pos = upper_bound(mark[i].begin