[P3694] 邦邦的大合唱站队(状压dp)

原题

思路

前缀和处理人数, 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;
}

同类型题

P3092 [USACO13NOV]No Change G

#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;
}
posted @ 2020-09-19 21:55  kurum!  阅读(115)  评论(0编辑  收藏  举报