HDU 5117 Fluorescent


题目描述:

Description

Matt, a famous adventurer who once defeated a pack of dire wolves alone, found a lost court. Matt finds that there are N fluorescent lights which seem to be the stars from the firmament. What’s more, there are M switches that control these fluorescent lights. Each switch is connected to a group of lights. When Matt touches a switch, all the lights connected to it will change their states (turning the dark on, turning the bright off).

Initially, all the fluorescent lights are dark. For each switch, Matt will touch it with probability 1 .

As a curious gentleman, Matt wants to calculate E[X3], where X represents the number of bright lights at the end, E[X3] represents the expectation of cube of X.

Input

The first line contains only one integer T , which indicates the number of test cases.

For each test case, the first line contains N, M (1 ≤ N, M ≤ 50), denoting the number of fluorescent lights (numbered from 1 to N ) and the number of switches (numbered from 1 to M ).

M lines follow. The i-th line begins with an integer Ki (1 ≤ K i ≤ N ). K i distinct integers l ij(1 ≤ l ij ≤ N ) follow, denoting the fluorescent lights that the i-th switch controls.

题解:

如果是求期望,那么因为期望的可加性,我们看每一个灯对答案的贡献,xi是0或者是1,有pi的概率,然后虽然是相关的,但是累加起来就好了.但是要求x^3的期望.我们把表达式写出来:先是EX的表达式:EX*2^m = (所有情况遍历)(x1+…+xn).因为期望的可加性,EX=(遍历n)(1*pi). 显然E(X^3)不能EX直接三次方.因为E(x^3)的含义是在某种情况下,把signma(x1+…+xn)搞一个三次方,之后的期望.因此我们把(signma(x1+…+xn))^3拆开.之后就有加法啦.然后利用期望的线性可加性就好算了.对于比如x1*x2*x3这种,显然都是1才有意义,那么我们需要计算都是1一共有多少种情况数.可以用dp[s]表示当前三个灯的状态,这样不用关注另外的灯的状态了.其实有一个小技巧,直接枚举三次1~n,不管ijk是谁,直接来一次就好了.具体看代码.

重点:

(1)期望的线性可加性:先利用指示器的思路把每一个变量的贡献写出来,然后写出期望的表达式,不好写就写出所有情况的和的形式.然后研究拆开成几个部分的加法,之后单独考虑加法就行了.

代码:
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>

using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
ll g[51],f[51][8],ans;
int n,m;
void solve()
{
    scanf("%d%d",&n,&m);
    //printf("%d %d\n",n,m);
    memset(g,0,sizeof g);
    ans = 0;
    for (int i = 1;i <= m;i++)
    {
        int num;
        scanf("%d",&num);
        for (int j = 1;j <= num;j++)
        {
            int x;
            scanf("%d",&x);
            g[i] |= (1ll << x);
        }
    }
    for (int i = 1;i <= n;i++)
        for (int j = 1;j <= n;j++)
            for (int k = 1;k <= n;k++)
            {
                memset(f,0,sizeof f);
                f[0][0] = 1;
                for (int no = 1;no <= m;no++)
                    for (int st = 0;st < (1<<3);st ++)
                    {
                        f[no][st] = (f[no][st] + f[no-1][st]) % mod;
                        int mask = 0;
                        if (g[no] & (1ll<<i)) mask |= 1;
                        if (g[no] & (1ll<<j)) mask |= 2;
                        if (g[no] & (1ll<<k)) mask |= 4;
                        //printf("%d %I64d\n",no,mask);
                        for (int stp = 0;stp < (1<<3);stp ++)
                        if ((stp ^ mask) == st)
                        {

                            f[no][st] = (f[no][st] + f[no-1][stp]) % mod;
                        }
                    }
                //printf("%I64d\n",f[m][8]);
                ans = (ans + f[m][7]) % mod;
            }
    static int ca = 0;
    printf("Case #%d: %I64d\n",++ca,ans);
}
int main()
{
   // freopen("in.txt","r",stdin);
    int t;
    scanf("%d",&t);
    while (t--)
        solve();
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值