By 三石吖 2026.2
- 最后一题没写
2.递归与分治
8594 有重复元素的排列问题
重点是知道有重复元素排列问题的去重方式,至于产生排列的顺序,会一种即可,本题做法了解即可
- 本题做法生成排列的顺序未必是字典序最优的
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int n;
std::string s;
std::cin >> n >> s;
int tot = 0;
auto dfs = [&] (auto &&self, int inx) -> void {
if(inx >= n){
std::cout << s << "\n";
tot++;
return;
}
auto check = [&] (int start, int end){
for(int i = start; i < end; i++){
if(s[i] == s[end]){
return true;
}
}
return false;
};
for(int i = inx; i < n; i++){
if(check(inx, i)){
continue;
}
std::swap(s[i], s[inx]);
self(self, inx + 1);
std::swap(s[i], s[inx]);
}
};
dfs(dfs, 0);
std::cout << tot << "\n";
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
#ifdef LOCAL
freopen("make.txt", "r", stdin);
freopen("a.txt", "w", stdout);
#endif
int T = 1;
// std::cin >> T;
while(T--){
solve();
}
return 0;
}
/*
*/
17088 分治法求众数
不会分治法。
排序法:
先排序然后双指针扫一遍
- 时间复杂度
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int n;
std::cin >> n;
std::vector<int>a(n);
for(int i = 0; i < n; i++){
std::cin >> a[i];
}
std::sort(a.begin(), a.end());
int cnt = 0, ans;
for(int i = 0, j; i < n; i = j){
j = i;
while(j < n && a[j] == a[i]){
j++;
}
if(j - i > cnt){
cnt = j - i;
ans = a[i];
}
}
std::cout << ans << " " << cnt << "\n";
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
#ifdef LOCAL
freopen("make.txt", "r", stdin);
freopen("a.txt", "w", stdout);
#endif
int T = 1;
// std::cin >> T;
while(T--){
solve();
}
return 0;
}
/*
*/
9714 圣诞礼物
发现好像可以直接!
考虑用 表示将个礼物放进个盒子,且每个盒子都不空的方法数
由于限制了每个盒子都不空,我们可以先往每个盒子中放进一个礼物,那么还剩个礼物,这个礼物可以放进个盒子中
于是得到了状态转移方程:
初始化,答案就是(因为个礼物最多放入个盒子,因此可以优化掉)
- 时间复杂度,此处的为
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int m, n;
std::cin >> m >> n;
n = std::min(m, n);
std::vector<std::vector<int>>dp(m + 1, std::vector<int>(n + 1));
dp[0][0] = 1;
for(int i = 1; i <= m; i++){
for(int j = 1; j <= std::min(n, i); j++){
for(int k = 0; k <= j ; k++){
dp[i][j] += dp[i - j][k];
}
}
}
int ans = 0;
for(int i = 0 ; i <= n; i++){
ans += dp[m][i];
}
std::cout << ans << "\n";
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
#ifdef LOCAL
freopen("make.txt", "r", stdin);
freopen("a.txt", "w", stdout);
#endif
int T = 1;
// std::cin >> T;
while(T--){
solve();
}
return 0;
}
/*
*/
求和部分可以用前缀和优化,这样每次加法都是的
- 时间复杂度,其中
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int m, n;
std::cin >> m >> n;
n = std::min(m, n);
std::vector<std::vector<int>>dp(m + 1, std::vector<int>(n + 1));
std::vector<std::vector<int>>pre(m + 1, std::vector<int>(n + 1));
dp[0][0] = 1;
for(int i = 0; i <= n; i++){
pre[0][i] = 1;
}
for(int i = 1; i <= m; i++){
for(int j = 1; j <= std::min(n, i); j++){
dp[i][j] += pre[i - j][j];
}
for(int j = 1; j <= n; j++){
pre[i][j] = pre[i][j - 1] + dp[i][j];
}
}
int ans = 0;
for(int i = 0 ; i <= n; i++){
ans += dp[m][i];
}
std::cout << ans << "\n";
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
#ifdef LOCAL
freopen("make.txt", "r", stdin);
freopen("a.txt", "w", stdout);
#endif
int T = 1;
// std::cin >> T;
while(T--){
solve();
}
return 0;
}
/*
*/
9718 整数因子分解
设为的分解式数量,依次枚举的大于的因数,将它们固定在第一位,问题转化为求
问题可以拆解为若干子问题,考虑递归求解
其中涉及大量重复计算,可用记忆化搜索优化
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int n;
std::cin >> n;
std::vector<int>f(n + 1);
f[1] = 1;
auto dfs = [&](auto &&self, int cur) -> int {
if(f[cur]){
return f[cur];
}
for(int i = 2; i <= std::sqrt(cur); i++){
if(cur % i){
continue;
}
f[cur] += self(self, cur / i);
if(i * i != cur){
f[cur] += self(self, i);
}
}
f[cur]++;
return f[cur];
};
int ans = dfs(dfs, n);
std::cout << ans << "\n";
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
#ifdef LOCAL
freopen("make.txt", "r", stdin);
freopen("a.txt", "w", stdout);
#endif
int T = 1;
// std::cin >> T;
while(T--){
solve();
}
return 0;
}
/*
*/
10302 整数的特殊划分
好像有很好的做法!
由于的幂次增长极快,以内的的幂次其实并不多,就算是级别,那也只会有种不同的的幂次
换句话说,我们可以先在常数级的复杂度内找到所有小于的的幂次,设其数量为
现在问题变成了 给定个不同的数,以及一个正整数,每个数可以重复取,问有多少种组成的方法数
或许这还不够直观,那么可以看成:
给定个不同的物品,以及一个容量,每个物品可以重复取,问有多少种容量为的填充方式
发现显然就是 完全背包 的板子题,直接即可
- 时间复杂度,为物品数量
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;
constexpr int mod = 1000000000;
void solve(){
int n;
std::cin >> n;
std::vector<int>a;
for(int i = 1; i <= n; i *= 2){
a.push_back(i);
}
int m = a.size();
std::vector<i64>dp(n + 1);
dp[0] = 1;
for(int i = 0; i < m; i++){
for(int j = a[i]; j <= n; j++){
dp[j] = (dp[j] + dp[j - a[i]]) % mod;
}
}
std::cout << dp[n] << "\n";
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
#ifdef LOCAL
freopen("make.txt", "r", stdin);
freopen("a.txt", "w", stdout);
#endif
int T = 1;
// std::cin >> T;
while(T--){
solve();
}
return 0;
}
/*
*/
10304 平面域着色
首先判掉不可能的情况:
①且
②且为奇数
用表示用种颜色给个区域染色的方法数
①若第个区域和第个区域同色,等价于给前个区域染色的方法数,此时第个区域有种染色方式,即为
②若第个区域和第个区域不同色,此时第个区域有种染色方式,为
即:
要初始化前三个数
- 时间复杂度
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int n, k;
std::cin >> n >> k;
if(k == 1 && n > 1){
std::cout << "0\n";
return;
}else if(k == 2 && n % 2){
std::cout << "0\n";
return;
}
if(n == 1){
std::cout << k << "\n";
return;
}else if(n == 2){
std::cout << k * (k - 1) << "\n";
return;
}else if(n == 3){
std::cout << k * (k - 1) * (k - 2) << "\n";
return;
}
std::vector<i64>dp(n + 1);
dp[1] = k, dp[2] = k * (k - 1), dp[3] = k * (k - 1) * (k - 2);
for(int i = 4; i <= n; i++){
dp[i] = dp[i - 2] * (k - 1) + dp[i - 1] * (k - 2);
}
std::cout << dp[n] << "\n";
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
#ifdef LOCAL
freopen("make.txt", "r", stdin);
freopen("a.txt", "w", stdout);
#endif
int T = 1;
// std::cin >> T;
while(T--){
solve();
}
return 0;
}
/*
*/
10343 划分凸多边形
给每个顶点按顺时针顺序标上,顶点可以将凸多边形划分成一个三角形,一个边形,一个边形,然后分解成了两个子问题,递归求解即可
- 时间复杂度
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int n;
std::cin >> n;
if(n < 3){
std::cout << "No answer\n";
return;
}
std::vector<int>f(n + 1 , -1);
f[2] = f[3] = 1;
auto dfs = [&](auto &&self, int x) -> int {
if(f[x] != -1){
return f[x];
}
f[x] = 0;
for(int i = 2; i < x; i++){
f[x] += self(self, i) * self(self, x - i + 1);
}
return f[x];
};
int ans = dfs(dfs, n);
std::cout << ans << "\n";
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
#ifdef LOCAL
freopen("make.txt", "r", stdin);
freopen("a.txt", "w", stdout);
#endif
int T = 1;
// std::cin >> T;
while(T--){
solve();
}
return 0;
}
/*
*/
10344 矩阵连乘积的加括号方式数
卡特兰数太难
本题就是求卡特兰数
- 时间复杂度
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int n;
std::cin >> n;
if(n <= 2){
std::cout << "1\n";
return;
}else if(n == 3){
std::cout << "2\n";
return;
}
std::vector<int>f(n + 1);
f[1] = f[2] = 1;
f[3] = 2;
auto dfs = [&](auto &&self, int x) -> int {
if(f[x]){
return f[x];
}
for(int i = 1; i < x; i++){
f[x] += self(self, i) * self(self, x - i);
}
return f[x];
};
int ans = dfs(dfs, n);
std::cout << ans << "\n";
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
#ifdef LOCAL
freopen("make.txt", "r", stdin);
freopen("a.txt", "w", stdout);
#endif
int T = 1;
// std::cin >> T;
while(T--){
solve();
}
return 0;
}
/*
*/
11073最热门的个搜索串
维护一个大小为的小顶堆,当堆的大小大于时,弹出堆顶
- 时间复杂度
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int n, k;
std::cin >> n >> k;
std::priority_queue<int, std::vector<int>, std::greater<>>que;
for(int i = 0; i < n; i++){
int x;
std::cin >> x;
que.push(x);
while(que.size() > k){
que.pop();
}
}
std::vector<int>res;
while(!que.empty()){
res.push_back(que.top());
que.pop();
}
for(int i = res.size() - 1; i >= 0; i--){
std::cout << res[i] << " \n"[i == 0];
}
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
#ifdef LOCAL
freopen("make.txt", "r", stdin);
freopen("a.txt", "w", stdout);
#endif
int T = 1;
// std::cin >> T;
while(T--){
solve();
}
return 0;
}
/*
*/
-
如果不要求选中的个元素有序,可以用
-
时间复杂度
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int n, k;
std::cin >> n >> k;
std::vector<int>a(n);
for(int i = 0; i < n; i++){
std::cin >> a[i];
}
std::nth_element(a.begin(), a.begin() + k, a.end(), std::greater<>());
for(int i = 0; i < n; i++){
std::cout << a[i] << " \n"[i == n - 1];
}
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
#ifdef LOCAL
freopen("make.txt", "r", stdin);
freopen("a.txt", "w", stdout);
#endif
int T = 1;
// std::cin >> T;
while(T--){
solve();
}
return 0;
}
/*
*/
11074 平面分割
看提示吧,好困难。
- 时间复杂度
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int n;
std::cin >> n;
i64 a = 1LL * n * (n + 1) / 2 + 1;
i64 b = 1LL * n * n - n + 2;
i64 c = 2LL * n * n - n + 1;
i64 d = (9LL * n * n - 7 * n) / 2 + 1;
std::cout << a << " " << b << " " << c << " " << d << "\n";
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
#ifdef LOCAL
freopen("make.txt", "r", stdin);
freopen("a.txt", "w", stdout);
#endif
int T = 1;
// std::cin >> T;
while(T--){
solve();
}
return 0;
}
/*
*/
11081 邮局选址
中位数定理,对横坐标和纵坐标分别选中位数即可
- 时间复杂度
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int n;
std::cin >> n;
std::vector<int>x(n), y(n);
for(int i = 0; i < n; i++){
std::cin >> x[i] >> y[i];
}
std::sort(x.begin(), x.end());
std::sort(y.begin(), y.end());
int r = x[n / 2], c = y[n / 2];
int ans = 0;
for(int i = 0; i < n; i++){
ans += std::abs(r - x[i]) + std::abs(c - y[i]);
}
std::cout << ans << "\n";
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
#ifdef LOCAL
freopen("make.txt", "r", stdin);
freopen("a.txt", "w", stdout);
#endif
int T = 1;
// std::cin >> T;
while(T--){
solve();
}
return 0;
}
/*
*/
11082 完全二叉树的种类(卡特兰数)
卡特兰数太难
本题就是求卡特兰数
- 时间复杂度
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int n;
std::cin >> n;
if(n <= 2){
std::cout << "1\n";
return;
}else if(n == 3){
std::cout << "2\n";
return;
}
std::vector<int>f(n + 1);
f[1] = f[2] = 1;
f[3] = 2;
auto dfs = [&](auto &&self, int x) -> int {
if(f[x]){
return f[x];
}
for(int i = 1; i < x; i++){
f[x] += self(self, i) * self(self, x - i);
}
return f[x];
};
int ans = dfs(dfs, n);
std::cout << ans << "\n";
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
#ifdef LOCAL
freopen("make.txt", "r", stdin);
freopen("a.txt", "w", stdout);
#endif
int T = 1;
// std::cin >> T;
while(T--){
solve();
}
return 0;
}
/*
*/
11085 买票找零(卡特兰数)
用表示有张元可以找零,还有人持元,人持元的方法数
然后跑记忆化搜索
初始化:时,若,则
时间复杂度:
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;
constexpr int N = 20;
int f[N][N][N];
void init(){
for(int i = 0; i < N; i++){
for(int j = 0; j < N; j++){
for(int k = 0; k < N; k++){
f[i][j][k] = -1;
}
}
}
for(int i = 0; i < N; i++){
for(int j = 0; j <= i; j++){
f[i][0][j] = 1;
}
}
}
void solve(){
init();
int n;
std::cin >> n;
auto dfs = [&](auto &&self, int cnt, int x, int y) -> int {
if(f[cnt][x][y] != -1){
return f[cnt][x][y];
}
f[cnt][x][y] = 0;
if(x){
f[cnt][x][y] += self(self, cnt + 1, x - 1, y);
}
if(cnt && y){
f[cnt][x][y] += self(self, cnt - 1, x, y - 1);
}
return f[cnt][x][y];
};
int ans = dfs(dfs, 0, n, n);
std::cout << ans << "\n";
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
#ifdef LOCAL
freopen("make.txt", "r", stdin);
freopen("a.txt", "w", stdout);
#endif
int T = 1;
// std::cin >> T;
while(T--){
solve();
}
return 0;
}
/*
*/
17083 多重幂计数问题
还是卡特兰数。
- 时间复杂度
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int n;
std::cin >> n;
if(n <= 2){
std::cout << "1\n";
return;
}else if(n == 3){
std::cout << "2\n";
return;
}
std::vector<int>f(n + 1);
f[1] = f[2] = 1;
f[3] = 2;
auto dfs = [&](auto &&self, int x) -> int {
if(f[x]){
return f[x];
}
for(int i = 1; i < x; i++){
f[x] += self(self, i) * self(self, x - i);
}
return f[x];
};
int ans = dfs(dfs, n);
std::cout << ans << "\n";
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
#ifdef LOCAL
freopen("make.txt", "r", stdin);
freopen("a.txt", "w", stdout);
#endif
int T = 1;
// std::cin >> T;
while(T--){
solve();
}
return 0;
}
/*
*/
17965 幸运之星
(1)只需要维护一个起点和当前剩下的人之间相邻的距离,发现这个距离必然相同,每过一轮这个距离都会,最多递归轮
(2)看提示,提示写的很详细了。注意应该用递推()写而不是递归。
- 时间复杂度
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int n, m;
std::cin >> n >> m;
auto dfs = [&](auto &&self, int start, int len) -> int {
if(start + len > n){
return start;
}
return self(self, start + len, len * 2);
};
int ans1 = dfs(dfs, 1, 1);
std::vector<int>dp(n + 1);
dp[1] = 1;
for(int i = 2; i <= n; i++){
dp[i] = (dp[i - 1] + m - 1) % i + 1;
}
std::cout << ans1 << " " << dp[n] << "\n";
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
#ifdef LOCAL
freopen("make.txt", "r", stdin);
freopen("a.txt", "w", stdout);
#endif
int T = 1;
// std::cin >> T;
while(T--){
solve();
}
return 0;
}
/*
*/
11086 排序问题再探讨
并非填空题,暴力即可
- 时间复杂度
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;
void solve(){
std::string s[] = {"Insert sort: ", "Natural merge sort: ", "Quick sort: "};
int n;
std::cin >> n;
std::vector<int>a(n);
for(int i = 0; i < 3; i++){
for(int j = 0; j < n; j++){
std::cin >> a[j];
}
std::sort(a.begin(), a.end());
std::cout << s[i];
for(int j = 0; j < n; j++){
std::cout << a[j] << " \n"[j == n - 1];
}
}
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
#ifdef LOCAL
freopen("make.txt", "r", stdin);
freopen("a.txt", "w", stdout);
#endif
int T = 1;
// std::cin >> T;
while(T--){
solve();
}
return 0;
}
/*
*/
11087 统计逆序对
树状数组的板子题
思路:
首先记录初始每个数的位置 然后对数组按值从大到小进行排序
然后 将排序后的数组中的数 按照原来的位置插入新数组
考虑如果当前插入的位置位 那么如果这个位置内已经有数插入 说明形成了逆序对
然后求总和即可
由于设计到动态更新前缀和以及多次查询,朴素前缀和会直接超时,所以得用树状数组
树状数组的单点修和区间查复杂度都是级别的
注意答案可能爆
- 时间复杂度
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;
template<typename T>
struct Fenwick{
std::vector<T>a;
int n;
Fenwick(int n_ = 0){
n = n_ + 1;
init();
}
void init(){
a.assign(n, T{});
}
void add(int pos, T k){
for(int i = pos; i < n; i += i & -i){
a[i] += k;
}
}
T sum(int pos){
T ans{};
for(int i = pos; i; i -= i & -i){
ans += a[i];
}
return ans;
}
T rangesum(int l, int r){
if(!l){
return sum(r);
}
else{
return sum(r) - sum(l - 1);
}
}
};
struct dat{
int val, id;
dat(): val(-1), id(-1){};
};
void solve(){
int n;
std::cin >> n;
std::vector<dat>a(n);
for(int i = 0; i < n; i++){
std::cin >> a[i].val;
a[i].id = i + 1;
}
std::sort(a.begin(), a.end(), [&](const dat &x, const dat &y){
if(x.val == y.val){
return x.id < y.id;
}
return x.val < y.val;
});
Fenwick<int>f(n);
i64 ans = 0;
for(int i = 0; i < n; i++){
int inx = a[i].id;
ans += f.rangesum(inx, n);
f.add(inx, 1);
}
std::cout << ans << "\n";
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
#ifdef LOCAL
freopen("make.txt", "r", stdin);
freopen("a.txt", "w", stdout);
#endif
int T = 1;
// std::cin >> T;
while(T--){
solve();
}
return 0;
}
/*
*/
11088 整数划分的扩展问题
(1)用所有的数做完全背包
(2)和问题(1)等价,具体证明可见提示,很妙
(3)用所有奇数做完全背包
(4)用所有以内的数做背包
- 时间复杂度:
- (1),(2):
- (3):
- (4):
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;
void get1(int n, int m){
std::vector<int>a(m);
for(int i = 0; i < m; i++){
a[i] = i + 1;
}
std::vector<int>dp(n + 1);
dp[0] = 1;
for(int i = 0; i < m; i++){
for(int j = a[i]; j <= n; j++){
dp[j] += dp[j - a[i]];
}
}
std::cout << dp[n] << " ";
}
void get3(int n){
std::vector<int>a;
for(int i = 1; i <= n; i += 2){
a.push_back(i);
}
std::vector<int>dp(n + 1);
dp[0] = 1;
int siz = a.size();
for(int i = 0; i < siz; i++){
for(int j = a[i]; j <= n; j++){
dp[j] += dp[j - a[i]];
}
}
std::cout << dp[n] << " ";
}
void get4(int n){
std::vector<int>a(n);
for(int i = 0; i < n; i++){
a[i] = i + 1;
}
std::vector<int>dp(n + 1);
dp[0] = 1;
for(int i = 0; i < n; i++){
for(int j = n; j >= a[i]; j--){
dp[j] += dp[j - a[i]];
}
}
std::cout << dp[n] << "\n";
}
void solve(){
int n, m;
std::cin >> n >> m;
get1(n, m);
get1(n, m);
get3(n);
get4(n);
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
#ifdef LOCAL
freopen("make.txt", "r", stdin);
freopen("a.txt", "w", stdout);
#endif
int T = 1;
// std::cin >> T;
while(T--){
solve();
}
return 0;
}
/*
*/
17082 两个有序数列中找第小
对两个序列一起跑双指针即可
- 时间复杂度,这主要来自输入两个序列的复杂度,找第小复杂度只有
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int n, m, k;
std::cin >> n >> m >> k;
std::vector<int>a(n), b(m);
for(int i = 0; i < n; i++){
std::cin >> a[i];
}
for(int i = 0; i < m; i++){
std::cin >> b[i];
}
int inxa = 0, inxb = 0, cnt = 0;
while(cnt < k - 1){
if(inxa >= a.size()){
cnt++;
inxb++;
}else if(inxb >= b.size()){
cnt++;
inxa++;
}else{
if(a[inxa] <= b[inxb]){
inxa++;
}else{
inxb++;
}
cnt++;
}
}
if(inxa >= a.size()){
std::cout << b[inxb] << "\n";
}else if(inxb >= b.size()){
std::cout << a[inxa] << "\n";
}else{
std::cout << std::min(a[inxa], b[inxb]) << "\n";
}
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
#ifdef LOCAL
freopen("make.txt", "r", stdin);
freopen("a.txt", "w", stdout);
#endif
int T = 1;
// std::cin >> T;
while(T--){
solve();
}
return 0;
}
/*
*/
17087 输出所有组合
排序后跑深搜即可
- 时间复杂度
#include<bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using pii = std::pair<int,int>;
using pll = std::pair<i64,i64>;
using pli = std::pair<i64,int>;
using pil = std::pair<int,i64>;
constexpr i64 INF = 0x3f3f3f3f3f3f3f3fll;
constexpr int inf = 0x3f3f3f3f;
void solve(){
int n;
std::string s;
std::cin >> n >> s;
std::sort(s.begin(), s.end());
std::vector<std::string>res;
std::string p;
auto dfs = [&](auto &&self, int inx) -> void {
if(!p.empty()){
res.push_back(p);
}
for(int i = inx; i < n; i++){
p += s[i];
self(self, i + 1);
p.pop_back();
}
};
dfs(dfs, 0);
std::sort(res.begin(), res.end(), [](const std::string &a, const std::string &b){
if(a.size() == b.size()){
return a < b;
}
return a.size() < b.size();
});
int siz = res.size();
for(int i = 0; i < siz; i++){
std::cout << i + 1 << " " << res[i] << "\n";
}
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
#ifdef LOCAL
freopen("make.txt", "r", stdin);
freopen("a.txt", "w", stdout);
#endif
int T = 1;
// std::cin >> T;
while(T--){
solve();
}
return 0;
}
/*
*/