首页 > 其他分享 >P3694 邦邦的大合唱站队 题解

P3694 邦邦的大合唱站队 题解

时间:2023-12-19 12:34:58浏览次数:36  
标签:状态 大合唱 int 题解 sum 预处理 P3694 dp

原题链接:P3694

思路

  • 状态设计

因为这道题 \(m\) 的范围非常小,所以可以用 \(m\) 来作为状态。设 \(dp_{i}\) 表示
\(m\) 支队伍的状态为 \(i\) 时最少让多少偶像出列。

  • 预处理

在转移之前,我们先要预处理出序列的前缀和 \(sum_{i,j}\) 表示第 \(i\) 个数之前有多少个值为 \(j\) 的数,方法如下:

for(int i = 1;i <= n;i++) 
	{
		cin >> a[i];
		for(int j = 1;j <= m;j++) sum[i][j] = sum[i - 1][j];
		sum[i][a[i]]++;
	}

还需要预处理出 \(s_{i}\) 表示 \(i\) 状态中一共有多少个人。只需要将状态 \(i\) 中的每一个数抽出来分解一下即可。

for(int i = 0;i < (1 << m);i++)
	{
		int now = i,cnt = 0;
		while(now != 0)
		{
			++cnt;
			if(now & 1) s[i] += sum[n][cnt];
			now >>= 1;
		}
	}
  • 方程转移

首先我们假设当前队伍是 \(j\),现在的状态是 \(i\),那么新加的需要出列的人就是 \(sum_{n,j}-sum_{s_{i},j}+sum_{s_{i xor (1<<j-1)}}\),相当于是用了前缀和的思想。所以 \(dp\) 方程转移为:

int l = s[i ^ (1 << j - 1)],r = s[i];
dp[i] = min(dp[i],dp[i ^ (1 << j - 1)] + sum[n][j] - sum[r][j] + sum[l][j]);

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ls id << 1
#define rs id << 1 | 1
#define inf 0x3f
#define inf_db 127
typedef pair <int,int> pii;
const int MAXN = 1e5 + 10;
const int MAXM = (1 << 20) + 10;
const int M = 30;
int n,m,a[MAXN],dp[MAXM],sum[MAXN][M],s[MAXM];
signed main()
{
	cin >> n >> m;
	for(int i = 1;i <= n;i++) 
	{
		cin >> a[i];
		for(int j = 1;j <= m;j++) sum[i][j] = sum[i - 1][j];
		sum[i][a[i]]++;
	}
	for(int i = 0;i < (1 << m);i++)
	{
		int now = i,cnt = 0;
		while(now != 0)
		{
			++cnt;
			if(now & 1) s[i] += sum[n][cnt];
			now >>= 1;
		}
	}
	memset(dp,inf,sizeof dp);
	dp[0] = 0;
	for(int i = 0;i < (1 << m);i++)
		for(int j = 1;j <= m;j++)
		{
			if(!(i & (1 << j - 1))) continue;
			int l = s[i ^ (1 << j - 1)],r = s[i];
			dp[i] = min(dp[i],dp[i ^ (1 << j - 1)] + sum[n][j] - sum[r][j] + sum[l][j]);
		}
	cout << dp[(1 << m) - 1];
	return 0;
}

标签:状态,大合唱,int,题解,sum,预处理,P3694,dp
From: https://www.cnblogs.com/Creeperl/p/17913450.html

相关文章

  • [AGC054C] Roughly Sorted 题解
    题意定义一种操作为交换\(a_{i}\)和\(a_{i-1}\)。对于一个长度为\(n\)的排列,你需要操作若干次,使这个序列变合法,一个序列合法指:满足对于每一个\(1\lei\len\),都满足包含\(a_i\)的逆序对的个数不超过\(k\),并且要求最小化操作次数。现在给定一个操作后的序列,询问原序列可......
  • P2391 白雪皑皑 题解
    原题链接:P2391。并查集好题。首先我们知道,并查集在一个无向图中可以维护两点之间的连通性,判断条件为:\(find(u)==find(v)\)。而对于这道题来说,我们可以用并查集来维护一个序列区间的重叠性或者说区间的连通性。因为题目上说了后面的操作会覆盖前面的操作,所以我们可以考虑倒序进行......
  • [ABC239Ex] Dice Product 2 题解
    原题链接:ABC239Ex。题意不多赘述。看到求期望值,我们想到可以用期望DP。设\(dp_{i}\)表示最终结果大于等于\(i\)时的操作次数的期望值。那么我们可以得到一个基本的状态转移方程:\(dp_{i}=\frac{1}{n}\times\sum_{j=1}^{n}dp_{\left\lceil\frac{i}{j}\right\rceil}+......
  • Prefix Purchase 题解
    题意给定一个长度为\(n\)的序列\(ans\),初始值全部为\(0\)。你一共有\(k\)个硬币,你可以选择花\(a_{i}\)个硬币来使\(ans_{1}\)到\(ans_{i}\)中的所有数加一。求最终能得到的\(ans\)序列中字典序最大的一个。思路首先我们可以发现一个很显然的性质:如果满足\(a_{i}......
  • Sum of XOR Functions 题解
    题意给定一个数\(n\)和一个包含\(n\)个数的序列\(a\),求出以下式子模\(998244353\)的值:\(\sum_{i=1}^{n}\sum_{j=i}^{n}f(i,j)\times(j-i+1)\)。其中\(f(i,j)\)的值为\(a_{i}\oplusa_{i+1}\oplusa_{i+2}\oplus...\oplusa_{j}\)。思路首先我们可以考虑这道题的......
  • Candy Party (Hard Version) 题解
    原题链接:CF1868B2,简单版:CF1868B1。题意有\(n\)个人,第\(i\)个人手上最初有\(a_{i}\)颗糖。现在每个人可以把自己手中的糖选一些给不多于一个人,同时每个人也只能接受不多于一个人的糖,选出的糖的数量必须是二的次幂。问能否能让每个人最终手上的糖的数量相等。思路首先,这......
  • 【0909 B组】切蛋糕 题解
    原题链接:切蛋糕。题意给定一个\(n\)行\(m\)列的蛋糕,问横着切\(i\)刀,竖着切\(j\)刀后美味度最小的蛋糕的美味度尽可能大。一块蛋糕的美味度为它所含有的小块的美味度之和。数据范围:\(1\len,m\le14\)。思路看到数据范围,我们可以考虑一种类似于状态压缩的思想,先枚举......
  • Cyclic Operations 题解
    前言看这道题有好多巨佬都是用Tarjan来做的,在这里讲一个自认为比较简单的做法,(不到\(30\)行)。题意题意比较难讲,建议自己去看一下翻译,在这里不多赘述。思路首先看到题目中间给的一个每一次操作的式子:\(a_{l_{i}}=l_{(i\modk)+1}\)。仔细观察这个式子后会发现,其实每一次......
  • P4630 [APIO2018] 铁人两项 题解
    今天学习了圆方树,并且做了一道和这道题很像的题,于是就又来做了一下这道题。题意给定一张不保证连通的无向图。求有多少个点对\((a,b,c)\)满足\(a\)到\(c\)的简单路径上经过了点\(b\)。思路显然圆方树。点双缩点过后构造一颗圆方树,然后考虑如何计算答案。圆方树有一个实......
  • [ABC315G] Ai + Bj + Ck = X (1 <= i, j, k <= N) 题解
    原题链接:ABC315G前置知识:扩展欧几里得算法。如果还不会扩欧的话,建议先去做这道题。题意给定\(n,a,b,c,k\)。求有多少个\(x,y,z(x,y,z\len)\)满足\(ax+by+cz=k\)。思路首先看到题目给出的方程式:\(ax+by+cz=k\)。我们会发现很像扩欧板子中的:\(ax+by=k\)。只不过又多了一......