题目<2016/11/30>

1.HDU5731
轮廓线状压DP+裸的容斥原理。
首先考虑没有任何限制的多米诺骨牌的问题。
那么我们暴力DP的话就是让不放的为0,放了的为1.
但是太暴力了,我们可以这样想。
对于第i个位置,我们实际上只关心第i个位置的:
这里写图片描述
如果我们知道这个轮廓线的所有状态,我们通过枚举这个格子怎么放也可以达到效果。
步骤如下:
1.枚举轮廓线状态以及在轮廓线的最后一个格子的状态。
2.更新下一个格子的轮廓线的状态,容易注意到,我们的轮廓线只是平移了一个单位。
3.所以我们用位运算表示轮廓线的位置,非常好做。

int f[2][1 << 17];
void Add(int s,int y)
{
    int &x = f[cur][s & ((1 << m) - 1)];
    if(s & (1 << m))x += y;
    if(x >= Mod)x -= Mod;
}
int solve()
{
    cur = 0;
    if(n < m)swap(n,m);
    int S = (1 << m) - 1;
    f[0][S] = 1;
    for(int i = 0;i < n;++ i)
    {
        for(int j = 0;j < m;++ j)
        {
            cur ^= 1;
            memset(f[cur],0,sizeof(f[cur]));
            for(int s = 0;s <= S;++ s)
            {
                Add((s << 1),f[cur ^ 1][s]);
                if(j && !(s & 1))Add( ((s << 1) | 3),f[cur ^ 1][s]);
                if(i && !(s & (1 << (m - 1))))Add((s << 1) | 1 | (1 << m),f[cur ^ 1][s]);
            }
        }
    }
    return f[cur][S];
}

注意向上的答案,需要用到 m+1 个元素。
就没别的好说的了。
预处理这个多米诺之后,我们通过容斥原理是很容易算出答案的。
有两个形式的容斥原理:
1.枚举至少满足每个状态,如果这个状态有偶数个1那么就减,否则就加。
2.枚举第一个违反条件的地方i,这个答案可以通过任意选减去第一次违反条件在j(j

void cal()
{
    while(~scanf("%d%d",&n,&m))
    {
        m --;
        int S = 1 << m,ans = 0;
        for(int s = 0;s < S;++ s) //枚举列的分割
        {
            int cur = 0,cnt = 0;
            for(int i = 0;i < m;++ i)
            {
                if(s & (1 << i))a[++ cnt] = 1 + cur,cur = 0;
                else ++ cur;
            }
            a[++ cnt] = cur + 1;
            for(int i = 1;i <= n;++ i)//枚举强制在第i行
            {
                for(int j = 0;j < i;++ j)
                {
                    int re = 1;
                    for(int k = 1;k <= cnt;++ k)
                        re = 1ll * re * f[a[k]][i - j] % Mod;
                    if(!j)dp[i] = re;
                    else dp[i] = (dp[i] - 1ll * re * dp[j] % Mod + Mod) % Mod;
                }
            }
            if(cnt & 1)ans = (ans + dp[n]) % Mod;
            else ans = (ans + Mod - dp[n]) % Mod;
        }
        printf("%d\n",ans);
    }
}

SRM664.DIV1T2
题意是:
给你棵树,以1为根。现在要炸这个树。
点i没炸掉的几率是1/i。
现在问所有联通块的大小的平方的期望值。
感觉很神,首先我们用奇怪的方法把平方去掉。
转成树上有序点对数目。
用dp[x]表示点x能到达子树(含自己)的期望点的个数。
那么 dp[x]=vson[x]dp[v]pr[x]
这个方程的意义在于, v 能到达的点在x没炸的时候一定能到达。
怎么算答案呢?
我们用类似于点分治的想法(并不),考虑过子树根的点对(路径)对答案的贡献,以及根本身对答案的贡献,可知一共分三种情况。
1.根本身:pr[x]
2.根到子树里面: pr[x]dp[v]
3.过根的路径: dp[v](dp[x]dp[v]pr[x])

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值