状压 dp
利用 的取值
- 一开始这就是状压 dp 模版
- 但是有时间要求,而且又要满足连续时间超过
,显然连续时间越大越好 - 那么
的取值就是最大连续时间 - 转移时可以根据
进行二分,总时间复杂度能够勉强通过
点击查看代码
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <set>
using namespace std;
using LL = long long;
using PII = pair<int, int>;
const int MAXN = 25 + 3, MAXK = 5e6 + 3;
const LL mod = 1e9 + 7;
struct st_cmp{
bool operator() (int i, int j) const {
return i > j;
}
};
int n, L;
set<int, st_cmp> st[MAXN];
int dp[MAXK], D[MAXN], cnt1[MAXK];
int main(){
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> L;
for(int i = 1, C; i <= n; i++){
cin >> D[i] >> C;
for(int j = 1, X; j <= C; j++){
cin >> X, st[i].insert(X);
}
}
for(int i = 1; i < (1ll << n); i++){
cnt1[i] = cnt1[i ^ (i & (-i))] + 1;
}
int ANS = 1e9;
for(int i = 0; i < (1ll << n); i++){
for(int j = 0; j < n; j++){
if((i >> j) % 2 == 0){
auto s = st[j + 1].lower_bound(dp[i]);
int _i = i + (1ll << j);
if(s != st[j + 1].end()){
dp[_i] = max(dp[_i], *s + D[j + 1]);
if(dp[_i] > L){
ANS = min(ANS, cnt1[_i]);
}
}
}
}
}
cout << (ANS >= 1e9 ? -1 : ANS);
return 0;
}
动态的状压 dp
表示 所表示的二进制数(0
为没有被选择,1
为已经被选择)- 这就会不断删除最后一个,不断加入第一个,可以通过位运算或取模来
计算 - 不断修改,在中途计算答案
点击查看代码
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <set>
using namespace std;
using LL = long long;
using PII = pair<int, int>;
const int MAXN = 1e5 + 3, MAXK = 300 + 3;
int n, k;
int a[MAXN];
int dp[MAXN][MAXK];
int gcd(int A, int B){
return !B ? A : gcd(B, A % B);
}
int main(){
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> k;
for(int i = 1; i <= n; i++){
cin >> a[i];
}
int ANS = 0;
for(int i = 1; i <= n; i++){
for(int j = 0; j < (1ll << k); j++){
int _j = (j * 2) % (1ll << k);
dp[i][_j] = max(dp[i][_j], dp[i - 1][j]);
ANS = max(ANS, dp[i][_j]);
}
for(int _k = 1; i - _k >= 1 && _k <= k; _k++){
int _i = i - _k;
if(gcd(a[i], a[_i]) > 1) continue;
for(int j = 0; j < (1ll << k); j++){
if((j >> (_k - 1)) % 2 == 0){
int _j = ((j + (1ll << (_k - 1))) * 2 + 1) % (1ll << k);
dp[i][_j] = max(dp[i][_j], dp[i - 1][j] + 1);
ANS = max(ANS, dp[i][_j]);
}
}
}
}
cout << ANS;
return 0;
}
类似前缀和的 dp
- 对于每个
请找到一个 使得 & - 对于
的每一位:- 如果当前这一位是
那么 的对应位就是 - 如果当前这一位是
那么 的对应位就是 或
- 如果当前这一位是
点击查看代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int MAXN = 1e6 + 3, MAXK = 5e6 + 3;
int n;
int a[MAXN];
int dp[MAXK];
int main(){
ios::sync_with_stdio(0), cin.tie(0);
cin >> n;
for(int i = 0; i < (1ll << 22); i++) dp[i] = -1;
for(int i = 1; i <= n; i++){
cin >> a[i], dp[a[i]] = a[i];
}
for(int i = 0; i < (1ll << 22); i++){
for(int j = 0; j < 22; j++){
if((i >> j) % 2 == 0){
dp[i + (1ll << j)] = max(dp[i + (1ll << j)], dp[i]);
}
}
}
for(int i = 1; i <= n; i++){
cout << dp[(1ll << 22) - 1 - a[i]] << " ";//
}
return 0;
}
本文作者:hhhqx
本文链接:https://www.cnblogs.com/huangqixuan/p/17612551.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步