NC 210732 灯谜

链接:https://ac.nowcoder.com/acm/problem/210732 来源:牛客网

题目描述

吉吉国王在探险的时候发现了一个奇怪的游戏,这个游戏有n盏灯,每盏灯刚开始都是熄灭的。有灯那么必然就有开关,吉吉国王在另外一侧发现了个开关,对于每个开关,都控制着一定数量的灯。对于每个开关,吉吉国王可以选择按一下,或者不按,每次按下,这个开关都会让其控制的灯的状态取反。 设x是最后亮着的灯的个数,现在需要求E(x3) * 2^m的值,EEE表示取期望。只需要输出在模1e9+7意义下的答案。

输入描述:
第一行两个整数n,m。
接下来m行,每行开头一个整数k表示第i个开关控制的灯的个数,接下来k个整数表示控制的灯的编号。
输出描述:
输出一个整数表示答案。

示例1

输入

复制

4 2
3 1 2 4
2 3 4
输出

复制

62
备注:
1≤n,m≤50 1≤k≤n

思路:这题是管道取珠的变形题:https://www.cnblogs.com/studyshare777/p/13601390.html

  首先看E(x3) * 2^m的物理意义,emm,其实就是按开关结果的期望 * 按开关的总方案数,就是x^3。

  求x^3,和管道取珠一样的思路,即加2个完全相同的装置,设灯i属于装置1,灯j属于装置2,灯k属于装置3,因为x^3就是3个装置亮的灯数量相同的方案数。所以当灯i,j,k都亮的时候,就是对答案有贡献。

  然后对每组(i,j,k),求他们同时亮的方案数:设f[t] [st],为对前t个开关操作过后,3个灯状态为st的方案数,st二进制位表示i,j,k的灯亮灭状态。

  显然有2种情况,不按第t个开关,f[t] [st]+=f[t-1] [st],按下第t个f[t] [st]+=f[t-1] [st'],状态st'按下开关后得到st。(具体注释在代码)

代码:

#include<iostream>
#include<algorithm>
#include<fstream>
#include<cstring>
#include<cstdio>
#include<sstream>
#include<vector>
#include<stack>
#include<deque>
#include<cmath>
#include<map>
#include<queue>
#include<bitset>
//#include<hash_map>
#define sd(x) scanf("%d",&x)
#define lsd(x) scanf("%lld",&x)
#define ms(x,y) memset(x,y,sizeof x)
#define fu(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define all(a) a.begin(),a.end()
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
//using namespace __gnu_cxx;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int maxn=1e5+79;
const int mod=1e9+7;
const int INF=1e9+7;
const double pi=acos(-1);

bool charge[56][56];
ll f[56][10];//f[t][st]:按前t个开关,3个灯状态为st
int n,m;
ll cal(int i,int j,int k)
{
    //计算i,j,k灯全亮的方案数
    ms(f,0);
    f[0][0]=1;
    fu(turn,1,m)
    {
        //当前开关
        fu(p,0,7)
        {
            //当前状态p,二进制位上,1表示亮,0表示不亮
            f[turn][p]+=f[turn-1][p];//不按第t个开关
            //上一个状态lp
            int lp=p;
            //按下开关,对应灯取反
            if(charge[turn][i]) lp=(lp^(1<<2));
            if(charge[turn][j]) lp=(lp^(1<<1));
            if(charge[turn][k]) lp=(lp^1);
            f[turn][p]+=f[turn-1][lp];//按下第t个开关
        }
    }
    return f[m][7];//3盏灯都亮方案数
}
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    //std::ifstream fil;
    //fil.open("t.txt");
    //freopen("C.in","r",stdin);
    cin>>n>>m;
    fu(i,1,m)
    {
        int k;cin>>k;
        fu(j,1,k) 
        {
            int x;cin>>x;
            //开关i控制灯x
            charge[i][x]=1;
        }
    }
    ll ans=0;
    fu(i,1,n)
    {
        fu(j,1,n)
        {
            fu(k,1,n)
            {
                //设为3个不同装置,枚举每个装置灯i,j,k
                ans=(ans+cal(i,j,k))%mod;
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}

 

posted on 2020-09-02 15:29  Aminers  阅读(209)  评论(0编辑  收藏  举报

导航