HDU5117 Fluorescent 期望 计数 状压dp 动态规划

原文链接https://www.cnblogs.com/zhouzhendong/p/HDU5117.html

题目传送门 - HDU5117

题意

  $T$ 组数据。

  给你 $n$ 盏灯 ,$m$ 个开关,每一个开关对应的控制一些灯。所有可以控制某盏灯的开关被按了奇数次,那么这盏灯最终是亮着的,否则是不亮的。

  现在每一个开关都可以选择按或者不按。我们称对于所有开关都做出 按或者不按 的一种选择 为一种 方案。一种方案的价值是其最终情况下灯数 $x$ 的三次方,即 $x^3$ 。

  求所有方案的价值和。答案对 $10^9+7$ 取模。

  $n,m\leq 50$

题解

  这题的做法真 妙 

  我们设一个方案的最终结果中,第 $i$ 栈灯的亮暗情况为 $x_i$ ,其中 $x_i=0$ 表示暗。

  那么这个方案的价值显然为:

$$(\sum_{i=1}^n x_i)^3 = \sum_{i,j,k\in[1,n]}x_ix_jx_k $$

  于是我们考虑对于每一个 $(i,j,k)$ ,求一下他对于最后答案的贡献。然后全部加起来。

  那么这个贡献怎么求呢?

  我们考虑状压dp,令 $dp_{i,j}$ 表示已经处理了前 $i$ 个灯,当前三盏灯亮暗状态为 $j$ 的贡献和,那么转移显然很 simple 。这样 $dp_{i,(亮,亮,亮)}$   显然就是当前贡献。

  时间复杂度 $O(Tn^4)$ 。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=55,mod=1e9+7;
int T,n,m,dp[N][8];
LL a[N];
int main(){
	scanf("%d",&T);
	int Case=0;
	while (T--){
		scanf("%d%d",&n,&m);
		memset(a,0,sizeof a);
		for (int i=1,s,x;i<=m;i++){
			scanf("%d",&s);
			while (s--)
				scanf("%d",&x),a[i]|=1LL<<x;
		}
		int ans=0;
		for (int i=1;i<=n;i++)
			for (int j=1;j<=n;j++)
				for (int k=1;k<=n;k++){
					memset(dp,0,sizeof dp);
					dp[0][0]=1;
					for (int t=1;t<=m;t++){
						int x=((a[t]>>i&1)<<2)|((a[t]>>j&1)<<1)|(a[t]>>k&1);
						for (int p=0;p<8;p++){
							dp[t][p]=(dp[t][p]+dp[t-1][p])%mod;
							dp[t][p^x]=(dp[t][p^x]+dp[t-1][p])%mod;
						}
					}
					ans=(ans+dp[m][7])%mod;
				}
		printf("Case #%d: %d\n",++Case,ans);
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/zhouzhendong/p/HDU5117.html

时间: 2024-09-29 17:34:50

HDU5117 Fluorescent 期望 计数 状压dp 动态规划的相关文章

动态规划---状压dp

状压dp,就是把动态规划之中的一个个状态用二进制表示,主要运用位运算. 这里有一道例题:蓝书P639猛兽军团1 直接上代码,注释很详细 #include<cstdio> #include<iostream> #include<cstring> #define N 15 #define M 110 #define MAX 550 using namespace std; /* 见蓝书641页 */ int s[MAX]; // 记录一行可能的状态 int num[MAX]

[bzoj3717][PA2014]Pakowanie_动态规划_状压dp

Pakowanie bzoj-3717 PA-2014 题目大意:给你n个物品m个包,物品有体积包有容量,问装下这些物品最少用几个包. 注释:$1\le n\le 24$,$1\le m\le 100$ 想法:以为是什么超级牛逼的背包dp,结果就是状压dp 状态:f[s]表示装s状态的物品需要多少背包,g[s]表示在f[s]的前提下,最大的背包剩余的容量. 转移:直接判断最后一个能不能装下当前物品,转移即可. 还有就是这个题卡常,只能直接用Lowbit枚举1,不能全枚举,会T... ... 最后

[bzoj1879][Sdoi2009]Bill的挑战_动态规划_状压dp

Bill的挑战 bzoj-1879 Sdoi-2009 题目大意: 注释:$1\le t \le 5$,$1\le m \le 15$,$1\le length \le 50$. 想法: 又是一个看数据范围想做法的题,我们想到状压dp. 看了题解... ...网上给的状态是f[len][s]表示长度为len满足状态s的字符串个数. 光看状态... ...可能算重啊?! 其实... ... 状态:dp[len][s]表示长度为len,能且只能满足状态为s的字符串个数. 转移:我们先预处理出g[i]

CF482C Game with Strings (状压DP+期望DP)

题目大意:甲和乙玩游戏,甲给出n(n<=50)个等长的字符串(len<=20),然后甲选出其中一个字符串,乙随机询问该字符串某一位的字符(不会重复询问一个位置),求乙能确定该串是哪个字符串的询问次数的期望值 这题不看题解好难想......(感谢zhx和zhx两位大佬的题解) len很小,考虑状压DP,显然我们要状压询问,要定义两个状态,f[]和num[] 1表示询问,0表示未询问 那么,我们定义f[s]表示询问状态s距离确定一个字符串所需要的期望值. 定义tot是s状态剩余的询问的次数,那么显

HDU 4336 容斥原理 || 状压DP

状压DP :F(S)=Sum*F(S)+p(x1)*F(S^(1<<x1))+p(x2)*F(S^(1<<x2))...+1; F(S)表示取状态为S的牌的期望次数,Sum表示什么都不取得概率,p(x1)表示的是取x1的概率,最后要加一因为有又多拿了一次.整理一下就可以了. 1 #include <cstdio> 2 const int Maxn=23; 3 double F[1<<Maxn],p[Maxn]; 4 int n; 5 int main() 6

【vijos】1286 座位安排(状压dp)

https://vijos.org/p/1286 这题好神不会捉... 首先我们知道所有情况有C(n*m, k)种,这个好搞.但是两两不相邻这个有点难搞.. 原来是状压dp..sigh. 设状态f[i][j][k]表示第i行放置的摆放状态是j放了k个人的方案,那么有 f[i][j][k]=sum{f[i-1][x][k-num[x]]},当j的人两两不冲突,且j和x的人两两不冲突,num[x]是x状态的人的数量 最后不冲突的数目是sum{f[n][j][k]},k是题目所给的,j是所有的状态 显

FZU 1025 状压dp 摆砖块

云峰菌曾经提到过的黄老师过去讲课时的摆砖块 那时百度了一下题目 想了想并没有想好怎么dp 就扔了 这两天想补动态规划知识 就去FZU做专题 然后又碰到了 就认真的想并且去做了 dp思想都在代码注释里 思想是很好想的..唯一的难点大概是 c++里面没有同或这种东西 得自己写 而我又不怎么会位运算 问了蕾姐半天也没搞懂怎么用~这个取反符号 到最后怒而手写了函数 一开始想的是 init后 输入nm都可以秒出 但是在使用~的路途上 发现至少我的方法 做这个题 不能做到init后随便输入 因为 每行 都有

牛客网 Wannafly挑战赛8 C-小C打比赛 (状压DP)

小C现在要参加一场wannafly挑战赛,一场挑战赛一共有n道题,一共有m分钟. 对于第i道题,小C解决它需要恰好j分钟的概率是pi,j. 小C每次会选择某一道没做完的题,然后把它解决(不能中途放弃),之后再决策下一道要做的题是哪道. 求小C在最优策略下,期望能做出几道题. 输入描述: 第一行两个正整数n,m接下来一共n行,每行有m个小数,第i行的第j个小数表示p i,j (这里假设不存在0分钟A题的dalao). 输出描述: 输出一个小数,表示期望能做出几道题,保留小数点后五位. 示例1 输入

状压DP初探&#183;总结

2018过农历新年这几天,学了一下状态压缩动态规划,现在先总结一下.   状态压缩其实是一种并没有改变dp本质的优化方法,阶段还是要照分,状态还是老样子,决策依旧要做,转移方程还是得列,最优还是最优,无后还是无后,所以它比较好理解.   状压,顾名思义就是要将一些状压想办法压缩起来(可以压,也可以删).其中这些状态都满足相似性和数量很多.这样才好压而且压得有意义.常见于一般的方格题,网络题等等.   所以一般基础的状压就是将一行的状态压成一个数,这个数的二进制形式反映了这一行的情况.所以位运算可