hdu 5117 状压DP

题意:
有M个开关,控制着N个灯,触碰一下开关,会把他所控制的灯的状态改变。对于M个开关你可以选择碰一次或者不碰,求最后开着多少个灯的三次方的期望值E(X^3)*2^m

题解:原式显然可以分解成X3      X=(x1+x2+x3...+xn),其中xi表示第i个灯的状态,题目就转化为求各个状态下X的立方的和

而X的立方可以看成是(x1+x2+x3...+xn)*(x1+x2+x3...+xn)*(x1+x2+x3...+xn)也就是xi*xj*xk的和,那么我们只要求出对于所有xi*xj*xk在所有状态中能为1的方法数,也就是i,j,k三灯全亮的方法数,加起来就是答案。用dp[i][j][k][ste][2]转移ste表示三个灯的状态,最后一个数组表示从处理前i个开关到处理前i+1个开关的滚动数组转移,注意滚动数组的初始化和DP不合法的判断

//#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <iostream>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
typedef long long ll;
#define CLR(x, v) sizeof (x, v, sizeof(x))
using namespace std;
const int INF = 0x5f5f5f5f;
const int mod=1e9 + 7;
const int maxn = 60;

int t,n,m;
int dp[maxn][maxn][maxn][10][2];
bool gra[maxn][maxn];
int main()
{
   //freopen("in","r",stdin);
   cin>>t;
   int cas = 0;
   while(t--){
        cas++;
        scanf("%d%d",&n,&m);
        int k,l;
        memset(dp,0,sizeof(dp));
        memset(gra,false,sizeof(gra));
        for(int i = 1;i <= m;i++){
            scanf("%d",&k);
            while(k--){
                scanf("%d",&l);
                gra[i][l] = true;
            }
        }
        int id = 0;

        memset(dp, 0, sizeof dp);

        for(int i = 1;i <= n;i++)
            for(int j = 1 ;j <= n;j++)
                for(int k = 1;k <= n;k++){
                   // if(i == j||j == k||i == k) continue;
                    dp[i][j][k][0][0] = 1;
                }
        for(int t = 1;t <= m;t++){

             for(int i = 1;i <= n;i++)
                for(int j = 1;j <= n;j++)
                    for(int k = 1;k <= n;k++)
                        for(int ste = 0;ste < 8;ste++)
                            dp[i][j][k][ste][id^1] = 0;

            for(int i = 1;i <= n;i++)
                for(int j = 1;j <= n;j++)
                    for(int k = 1;k <= n;k++){
                       // if(i == j||j == k||i == k) continue;
                        for(int ste = 0;ste < 8;ste++){
                            if (dp[i][j][k][ste][id] == 0) continue;
                            dp[i][j][k][ste][id^1] += dp[i][j][k][ste][id];
                            dp[i][j][k][ste][id^1] %= mod;
                            int ans = ste;
                            if(gra[t][i])
                                ans ^= 1;
                            if(gra[t][j])
                                ans ^= 2;
                            if(gra[t][k])
                                ans ^= 4;
                            dp[i][j][k][ans][id^1] += dp[i][j][k][ste][id];
                            dp[i][j][k][ans][id^1] %= mod;
                           // cout<<t<<" "<<i<<" "<<j<<" "<<k<<" "<<ans<<" "<<dp[i][j][k][ans][id^1]<<endl;
                        }

                    }
            id ^= 1;
        }
      //  cout<<n<<endl;
        int sum = 0;
        for(int i = 1;i <= n;i++)
            for(int j = 1;j <= n;j++)
                for(int k = 1;k <= n;k++){
                    sum += dp[i][j][k][7][id];
                    sum %= mod;
                }
        printf("Case #%d: %d\n",cas,sum);
   }
   return 0;
}
时间: 2024-08-05 03:49:34

hdu 5117 状压DP的相关文章

HDU 4284 状压dp+spfa堆优化

题意: 给定n个点 m条无向边 d元. 下面m行表示每条边 u<=>v 以及花费 w 下面top 下面top行 num c d 表示点标为num的城市 工资为c 健康证价格为d 目标是经过给定的top个城市,当到达该城市时,必须马上购买该城市的健康证并打工赚钱(每个城市只打工1次) 问从1城市出发,最后回到1城市,能否收集到所有的健康证 思路: 由于top很小,所以状压dp dp[i][tmp]表示当前处于i点 经过城市的状态为tmp时 身上最多的钱. 首先对dis数组floyd 跑出最短路,

hdu 4906 状压dp

/* ID: neverchanje PROG: LANG: C++11 */ #include<vector> #include<iostream> #include<cstring> #include<string> #include<algorithm> #include<cmath> #include<cstdio> #include<set> #include<queue> #includ

HDU 4892 状压dp

[BestCoder Round #5]冠军的奖励是小米3手机一部 恭喜福州大学杨楠获得[BestCoder Round #4]冠军(iPad Mini一部) <BestCoder用户手册>下载 Defence of the Trees Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 224    Accepted Submiss

HDU 3001 状压DP

有道状压题用了搜索被队友骂还能不能好好训练了,, hdu 3001 经典的状压dp 大概题意..有n个城市 m个道路  成了一个有向图.n<=10: 然后这个人想去旅行.有个超人开始可以把他扔到任意的一个城市..然后他就在城市之间游荡.要满足他要游玩所有的城市..并且.每个城市最多去两次.要求路程最短..如果他不能游完所有的城市,,那么..就输出-1  否则 输出最短距离 如果用搜索...不靠谱  然后用搜索,, 怎么压缩?? 用一个整型数 i 表示他现在的状态..显然一个城市是要用两位..00

Travel(HDU 4284状压dp)

题意:给n个城市m条路的网图,pp在城市1有一定的钱,想游览这n个城市(包括1),到达一个城市要一定的花费,可以在城市工作赚钱,但前提有工作证(得到有一定的花费),没工作证不能在该城市工作,但可以走,一个城市只能工作一次,问pp是否能游览n个城市回到城市1. 分析:这个题想到杀怪(Survival(ZOJ 2297状压dp) 那个题,也是钱如果小于0就挂了,最后求剩余的最大钱数,先求出最短路和 Hie with the Pie(POJ 3311状压dp) 送披萨那个题相似. #include <

hdu 1185 状压dp 好题 (当前状态与上两行有关系)

/* 状压dp 刚开始&写成&&看了好长时间T0T. 状态转移方程 dp[i][k][j]=Max(dp[i][k][j],dp[i-1][l][k]+num[i][j]);(第i行的第j个状态有上一行的第k个状态得到) num[i][j]有两个功能,第一:判断第i行第j个状态是否合法 第二:判断第i行第j个状态的数目 */ #include<stdio.h> #include<string.h> #define N 110 int dp[N][N][N];

HDU 5823 (状压dp)

Problem color II 题目大意 定义一个无向图的价值为给每个节点染色使得每条边连接的两个节点颜色不同的最少颜色数. 对于给定的一张由n个点组成的无向图,求该图的2^n-1张非空子图的价值. n <= 18 解题分析 官方题解: 直接状压dp就行了,f[S]表示点集S的色数,枚举子集转移(子集是独立集).这样是3^n的. 一个复杂度更优的做法是把所有独立集都预处理出来,然后作n次or卷积.这样是n^2*2^n的. 枚举子集的子集的时间复杂度是3^n 啊 . 即 sigma( C(n,k

hdu 3254 (状压DP) Corn Fields

poj 3254 n乘m的矩阵,1表示这块区域可以放牛,0,表示不能,而且不能在相邻的(包括上下相邻)两个区域放牛,问有多少种放牛的方法,全部不放也是一种方法. 对于每块可以放牛的区域,有放或者不放两种选择,状压DP,dp[i][j]表示第 i 行以state[j]这种状态的时候和方法取值. 具体的参考http://www.tuicool.com/articles/JVzMVj 写的很详细. 1 #include<cstdio> 2 #include<cstring> 3 #inc

HDU 6321 (状压dp)

题目大意:: 为给你n个点(n<=10,nn<=10,n) 初始时没有边相连 然后有m个操作(m<=30000m<=30000) 每次可以添加一条边或删除一条边 允许有重边 要求每次操作过后输出选这个图中不相交的k条边有多少种不同的方案 (k=1,2,3--n/2) 题目分析: n最大只有10 , 所以很容易就可以想到状压DP , 但是我在打的时候并没有想出继承状态 , 后来看了题解才略有一丝感悟: 首先一个特别容易看出的状态是每加/减一条边后的状态是由前一个状态转移过来的 : 而