Luogu P3694 邦邦的大合唱站队 【状压dp】By cellur925

题目传送门

最开始学状压的时候...学长就讲的是这个题。当时对于刚好像明白互不侵犯和炮兵阵地的我来说好像在听天书......。因为我当时心里想,这又不是什么棋盘,咋状压啊?!后来发现这样的状压多了去了hhh。后来这道题就一直压着了,现在对状压明白了一点便来填坑。



我们注意到,团体队员数$N$比较大,而团体数$M$很小(不能称为乐队)。那么我们可以在$m$上下功夫,把它压成二进制串。开始想的状态是0表示这个团体还没站好,1表示这个团体已经站好了。看了看jtdalao的文章发现自己的状态是对的,但是转移嘛...,有点迷感觉。一步一步来。首先我们肯定要枚举当前的状态是什么,按照状压dp的套路,我们接下来要枚举下这一次新站好的是哪个队。转移时我们需要用在新队站好前的状态所需的次数+站成新队另需要的人数。我们默认大家都是排成一列紧跟在一个人之后的,所以我们需要求出当前已经排到谁了。所以我们还需要开一个数组前缀和来记录排队的信息。设$sum[i][j]$表示到$i$位置,$j$团体的人数。

转移有:

$f[i]$=$min$$($f[i^(1<<j)]$+$num[j]$-($sum[pos][j]$-$sum[pos-num[j]][j]$))。

因为当前新加的段之前也可能有本队队员,所以把他们减去。

初值,因为求最小,所以开始赋成极大,$f[0]=0$。(边界)

之后就比较好想了==。



$Code$

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4
 5 using namespace std;
 6
 7 int n,m,fAKe;
 8 int f[1<<23],num[50],sum[100090][25];
 9
10 int main()
11 {
12     scanf("%d%d",&n,&m);
13     for(int i=1;i<=n;i++)
14     {
15         int x=0;
16         scanf("%d",&x);
17         num[x-1]++;
18         sum[i][x-1]++;
19         for(int j=0;j<m;j++)
20             sum[i][j]+=sum[i-1][j];
21     }
22     fAKe=(1<<m)-1;
23     memset(f,0x3f,sizeof(f));
24     f[0]=0;
25     for(int i=0;i<=fAKe;i++)
26     {
27         int pos=0;
28         for(int j=0;j<m;j++)
29             if(i&(1<<j)) pos+=num[j];
30         for(int j=0;j<m;j++)
31             f[i]=min(f[i],f[i^(1<<j)]+num[j]-(sum[pos][j]-sum[pos-num[j]][j]));
32     }
33     printf("%d\n",f[fAKe]);
34     return 0;
35 }

原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9736340.html

时间: 2024-10-04 08:53:19

Luogu P3694 邦邦的大合唱站队 【状压dp】By cellur925的相关文章

【Luogu】P1896互不侵犯King(状压DP)

题目链接 真是可恶,被数据范围坑了一把.想要一遍AC的希望破灭了…… 以后大家在做状压DP的时候一定要开long long…… 设f[i][j][k]表示考虑前i行,总共放了j个King,第i行状态为k时的方案数. 先统计出k的二进制位有多少1,记为len,然后枚举o(1~(1<<n)-1),则状态转移方程有: f[i][j][l]+=f[i-1][j-len][o]; 注意判断两个状态是否合法. j&(j>>1)不行,o&j不行,(o>>1)&

P3694 邦邦的大合唱站队/签到题(状压dp)

P3694 邦邦的大合唱站队/签到题 题目背景 BanG Dream!里的所有偶像乐队要一起大合唱,不过在排队上出了一些问题. 题目描述 N个偶像排成一列,他们来自M个不同的乐队.每个团队至少有一个偶像. 现在要求重新安排队列,使来自同一乐队的偶像连续的站在一起.重新安排的办法是,让若干偶像出列(剩下的偶像不动),然后让出列的偶像一个个归队到原来的空位,归队的位置任意. 请问最少让多少偶像出列? 输入输出格式 输入格式: 第一行2个整数N,M. 接下来N个行,每行一个整数a_i(1\le a_i

[luoguP3694] 邦邦的大合唱站队/签到题(状压DP)

传送门 来自kkk的题解: 70分做法:枚举每个学校顺序,暴力. 100分:状压dp.从队列头到尾DP, 状态:f[i]表示i状态下最小的出列(不一致)的个数. 比如f[1101]表示从头到位为1/3/4乐队的偶像的最小出列个数. f[i]=min(f[i\ xor\ 2^j]+num[j]-(sum[length][j]-sum[length-num[j]][j]));f[i]=min(f[i xor 2?j??]+num[j]−(sum[length][j]−sum[length−num[j

dp乱写2:状态压缩dp(状压dp)炮兵阵地

https://www.luogu.org/problem/show?pid=2704 题意: 炮兵在地图上的摆放位子只能在平地('P') 炮兵可以攻击上下左右各两格的格子: 而高原('H')上炮兵能够攻击到但是不能摆放 求最多能摆放的炮兵的数量 就是这个意思. 难度提高,弱省省选 一开始是想写dfs(迷之八皇后)的, 但是看到数据量100就想dp了: 因为题目n的范围给的很少n<=10,想到状压 非常明显是一个状态压缩的dp(状压dp) 其实可以当做状压的入门题目来做. 由于本行的状态是由前若

【一天一DP计划】状压DP

##P1896 互不侵犯[状压dp] 用01串表示每一行的可行解 列与列之间的限制条件在转移的时候continue x&=(-x)可以找到x的二进制位上有多少个1 关于位运算的优先级!不确定就无脑加括号哦哦 reference: https://www.luogu.org/blog/virus2017/1896dnqec Date: 2019.10.04 */ #include<bits/stdc++.h> using namespace std; #define int long l

[USACO06NOV]Corn Fields(状压DP)

https://www.luogu.com.cn/problem/P1879 题目描述 Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yummy corn for the cows on a number of squares. Regrettably, some o

ZOJ3305Get Sauce 状压DP,

状压DP的题目留个纪念,首先题意一开始读错了,搞了好久,然后弄好了,觉得DFS可以,最后超时,修改了很久还是超时,没办法看了一下n的范围,然后觉得状压可以,但是没有直接推出来,就记忆化搜索了一下,可是一直错,莫名奇妙,然后没办法看了一下题解,发现了下面这个比较好的方法,然后按照这个方程去推,然后敲,也是WA了好多把,写的太搓了,没人家的清楚明了,唉~也算是给自己留个纪念,状压一直做的都不太好~唉~还好理解了, 参考了  http://blog.csdn.net/nash142857/articl

poj 2411 Mondriaan&#39;s Dream(状压DP)

Mondriaan's Dream Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 12232   Accepted: 7142 Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series

(状压dp)uva 10817 Headmaster&#39;s Headache

题目地址 1 #include <bits/stdc++.h> 2 typedef long long ll; 3 using namespace std; 4 const int MAX=1e5+5; 5 const int INF=1e9; 6 int s,m,n; 7 int cost[125]; 8 //char sta[MAX]; 9 string sta; 10 int able[125]; 11 int dp[125][1<<8][1<<8]; 12 in