题目<2016/11/30>

来源:互联网 发布:g3营销软件 编辑:程序博客网 时间:2024/05/22 14:11

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])

0 0
原创粉丝点击