[P3694] 邦邦的大合唱站隊(狀壓dp)
阿新 • • 發佈:2020-09-20
原題
思路
字首和處理人數, 10表示是否有序,經行狀壓,列舉當前狀態最後一個有序的樂隊。
#include <algorithm> #include <climits> #include <cmath> #include <cstdio> #include <cstring> #include <list> #include <map> #include <iostream> #include <iomanip> #include <queue> #include <set> #include <stack> #include <string> #include <vector> #define LL long long #define inf 0x3f3f3f3f #define INF 0x3f3f3f3f3f3f #define PI 3.1415926535898 #define F first #define S second #define endl '\n' #define lson rt << 1 #define rson rt << 1 | 1 #define f(x, y, z) for (int x = (y), __ = (z); x < __; ++x) #define _rep(i, a, b) for (int i = (a); i <= (b); ++i) using namespace std; const int maxn = 1e5 + 7; const int maxm = 25; const int mod = 1e9 + 7; int n, m; int bel[maxn]; int sum[maxn][maxm]; int dp[1 << 21]; int main() { ios::sync_with_stdio(false); cin.tie(0); cin >> n >> m; _rep(i, 1, n) { cin >> bel[i]; _rep(j, 1, m) sum[i][j] = sum[i - 1][j]; sum[i][bel[i]]++; } _rep(i, 1, 1 << m) dp[i] = inf; f(i, 1, 1 << m) { int len = 0; _rep(j, 1, m) if (i & (1 << j - 1)) len += sum[n][j]; _rep(j, 1, m) { if (!(i & (1 << j - 1))) continue; int tmp = 1 << j - 1; dp[i] = min(dp[i], dp[i ^ tmp] + sum[n][j] - sum[len][j] + sum[len - sum[n][j]][j]); } } cout << dp[(1 << m) - 1] << endl; }
同類型題
#include <algorithm> #include <climits> #include <cmath> #include <cstdio> #include <cstring> #include <list> #include <map> #include <iostream> #include <iomanip> #include <queue> #include <set> #include <stack> #include <string> #include <vector> #define LL long long #define inf 0x3f3f3f3f #define INF 0x3f3f3f3f3f3f #define PI 3.1415926535898 #define F first #define S second #define endl '\n' #define lson rt << 1 #define rson rt << 1 | 1 #define f(x, y, z) for (int x = (y), __ = (z); x < __; ++x) #define _rep(i, a, b) for (int i = (a); i <= (b); ++i) using namespace std; const int maxn = 1e5 + 7; const int maxm = 25; const int mod = 1e8; int n, m; int dp[1 << 16]; int coin[17], a[maxn], sum[maxn]; int main() { ios::sync_with_stdio(false); cin.tie(0); cin >> m >> n; int ans = inf, tot = 0; _rep(i, 1, m) { cin >> coin[i]; tot += coin[i]; } _rep(i, 1, n) { cin >> a[i]; sum[i] = sum[i - 1] + a[i]; } sum[n + 1] = 1e9; f(i, 0, 1 << m) { int tmp = 0; f(j, 0, m) if (i & (1 << j)) tmp += coin[j + 1]; f(j, 0, m) { if (i & (1 << j)) { int temp = dp[i ^ (1 << j)]; int nxt = upper_bound(sum + temp, sum + n + 1, coin[j + 1] + sum[temp]) - sum; nxt -= 1; dp[i] = max(dp[i], dp[i ^ (1 << j)] + nxt - temp); if (dp[i] == n) ans = min(ans, tmp); } } } cout << ((tot - ans >= 0)?tot - ans: -1)<< endl; }