hihocoder #1071 : 小玩具

闻所未闻的$dp$神题(我不会的题)

令$f[S][i]$表示子集状态为$S$,且$S$中最大联通块恰好为$i$的方案数

考虑转移,我们枚举$S$中最小的元素$v$来转移,这样就能不重

$f[S][i] = \sum\limits_{T \in S \;and\;v \in T} f[T][...] * C[S \wedge T]$

由于这么递归转移不好确定后面的状态,因此我们可以递推转移,在代码中有所体现

$C[S]$表示将$S$联通的方案数

我们考虑容斥,用全集减去所有不联通的方案数,我们考虑枚举最小点$v$所在的集合

之后转移时$C[S] = 2^{E[S]} - \sum\limits_{T \in s \;ans\;v\; \in T} C[T] * 2^{E[S \wedge T]}$

其中,$E[S]$表示处于$S$内部的边的方案数

复杂度$O(3^n * n)$

#include <set>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
namespace remoon {
    #define re register
    #define de double
    #define le long double
    #define ri register int
    #define ll long long
    #define sh short
    #define pii pair<int, int>
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    #define tpr template <typename ra>
    #define rep(iu, st, ed) for(ri iu = st; iu <= ed; iu ++)
    #define drep(iu, ed, st) for(ri iu = ed; iu >= st; iu --)
    #define gc getchar
    inline int read() {
        int p = 0, w = 1; char c = gc();
        while(c > ‘9‘ || c < ‘0‘) { if(c == ‘-‘) w = -1; c = gc(); }
        while(c >= ‘0‘ && c <= ‘9‘) p = p * 10 + c - ‘0‘, c = gc();

        return p * w;
    }
    int wr[50], rw;
    #define pc(iw) putchar(iw)
    tpr inline void write(ra o, char c = ‘\n‘) {
        if(!o) pc(‘0‘);
        if(o < 0) o = -o, pc(‘-‘);
        while(o) wr[++ rw] = o % 10, o /= 10;
        while(rw) pc(wr[rw --] + ‘0‘);
        pc(c);
    }
    tpr inline void cmin(ra &a, ra b) { if(a > b) a = b; }
    tpr inline void cmax(ra &a, ra b) { if(a < b) a = b; }
    tpr inline bool ckmin(ra &a, ra b) { return (a > b) ? a = b, 1 : 0; }
    tpr inline bool ckmax(ra &a, ra b) { return (a < b) ? a = b, 1 : 0; }
}
using namespace std;
using namespace remoon;

#define sid 17
#define mod 1000000007

inline void inc(int &a, int b) { a += b; if(a >= mod) a -= mod; }
inline void dec(int &a, int b) { a -= b; if(a < 0) a += mod; }
inline int mul(int a, int b) { return 1ll * a * b % mod; }

int pc[2555];
int u[555], v[555];
int E[(1 << 16) + 5000], C[(1 << 16) + 5000];
int f[(1 << 16) + 5000][sid];
int n, m;

int main() {

    n = read(); m = read(); pc[0] = 1;
    rep(i, 1, 1000) pc[i] = mul(pc[i - 1], 2);
    rep(i, 1, m) u[i] = read(), v[i] = read();

    rep(S, 0, (1 << n) - 1) rep(i, 1, m)
    if((S & (1 << u[i] - 1)) && (S & (1 << v[i] - 1))) ++ E[S];

    C[0] = 1;
    rep(S, 1, (1 << n) - 1) {
        int res = pc[E[S]], mi = -1;
        rep(i, 1, n) if(S & (1 << i - 1)) { mi = i; break; }
        for(ri T = S & (S - 1); T; T = (T - 1) & S)
        if(T & (1 << mi - 1)) dec(res, mul(C[T], pc[E[S ^ T]]));
        C[S] = res;
    }

    f[0][0] = 1;
    rep(S, 0, (1 << n) - 1) rep(j, 0, n) if(f[S][j]) {
        int mi = -1;
        rep(i, 1, n) if(!(S & (1 << i - 1))) { mi = i; break; }
        if(mi == -1) continue;
        int D = ((1 << n) - 1) ^ (S | (1 << mi - 1));
        for(ri T = D; ; T = (T - 1) & D) {
            int st = __builtin_popcount(T | (1 << mi - 1));
            inc(f[S | (1 << mi - 1) | T][max(j, st)], mul(f[S][j], C[(1 << mi - 1) | T]));
            if(!T) break;
        }
    }

    rep(i, 1, n)
    write(f[(1 << n) - 1][i]);

    return 0;
}

原文地址:https://www.cnblogs.com/reverymoon/p/9800998.html

时间: 2024-11-14 06:23:44

hihocoder #1071 : 小玩具的相关文章

#1071 : 小玩具

描述 某天,高富帅clj送了他的朋友jzp一个小玩具. 这个玩具可以被看成是一个n个点,m条边的没有重边和自环的无向图.对于每一条边,有闪光和黑暗两种状态. jzp可以把一些边设为闪光,一些边设为黑暗.当jzp设置完成以后,这个玩具会按照如下方式计算出一个分数.首先称闪光边和这n个点组成的图为导出子图,然后玩具会找出导出子图中最大的联通分量的大小,当做分数输出. jzp有一天很闲,他尝试了所有的2m种边的设置方式(每个边为闪光或者黑暗),并且计算出了每种分数的出现次数.写在了一张纸上. 但是很不

开源项目之小玩具---各种机器人开源硬件

一些小玩具的网站 作者: doskey 日期: 2012 年 10 月 10 日1 条评论 TinkerForge - http://www.tinkerforge.com一个开源机器人的网站.Made In Germany.东西很好只是太贵. Arduino – http://www.arduino.cc著名的开源电路项目.价格不便宜.适合爱折腾的同学. Raspberry Pi – http://www.raspberrypi.org现在最火爆的开源电路板——树莓派.东西便宜,可玩性高,但是

hihocoder#1513 : 小Hi的烦恼 bitset

目录 题目链接 题解 代码 题目链接 hihocoder#1513 : 小Hi的烦恼 题解 cdq 套cdq 套cdq 套cdq就完了呀 对每一科开n个bitset 表示该科目前i个有谁 每次查询都&起来就好了 代码 #include<cstdio> #include<bitset> #include<cstring> #include<algorithm> #define LL long long #define gc getchar() #def

hihocoder 1191 小W与网格 (组合数)

时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个n*m的网格,左上角(1, 1),右下角(n, m). 小w在(i, j),他会从"上左下右"四个方向中选定两个不同但正交的方向,然后他只能沿着这两个方向走,直到他走出网格. 小w想知道有多少种不同的走法. 两个走法不同当且仅当所经过的格子的集合不同. 输入 输入包含多组数据. 每组数据一行四个整数n, m, i, j.(1 <= i <= n <= 100, 1 <= j &l

HihoCoder 1570 : 小Hi与法阵(简单几何)

描述 小Hi喜欢大,而小Ho喜欢小.他们所在的城市(视为二维平面)有N座法阵.现在他们各选三座法阵,以三座法阵为顶点组成三角形,并站在所选三角形的重心位置:二人选择的法阵可以有相同的.小Hi选择面积最大的三角形,小Ho选择面积最小的三角形.若有多个面积相同且符合他们要求的三角形,小Hi选择重心横坐标最大的,若重心横坐标相同,则选择重心纵坐标最大的:小Ho选择重心横坐标最小的,若重心横坐标相同,则选择重心纵坐标最小的. 现在两人需要见面,两人均可以在城市里以不超过U的速度向任意方向移动,问他们两个

HihoCoder 1638 : 小Hi的天平 (2-sat+并查集)

描述 小Hi给小Ho邮寄了一个天平.收到天平后,小Ho想知道天平在运输过程中是否损坏,为此它准备了A类物品和B类物品共n个(可能只有A类物品,也可能只有B类物品),但无法确定一个物品是哪一类.A类物品的质量都相同,B类物品的质量也相同,但A类物品与B类物品的质量不同.现将n个物品从1到n编号,用天平进行m次测量,每次从n个物品中取i和j两个物品,测量后可以知道物品i和物品j质量是否相同. 现在小Ho想知道能否根据测量结果判定天平是坏的,如果能确定,最早是第几次测量确定的,你能帮帮他吗? 输入 第

HihoCoder 1473 : 小Ho的强迫症

描述 小Ho在一条笔直的街道上散步.街道上铺着长度为L的石板,所以每隔L距离就有一条石板连接的缝隙,如下图所示. 小Ho在散步的时候有奇怪的强迫症,他不希望脚踩在石板的缝隙上.(如果小Ho一只脚的脚尖和脚跟分别处于一条缝隙的两侧,我们就认为他踩在了缝隙上.如果只有脚尖或脚跟接触缝隙,不算做踩在缝隙上) 现在我们已知小Ho两只脚的长度F以及每一步步伐的长度D.如果小Ho可以任意选择起始位置,请你判断小Ho能否保持不踩缝隙散步至无穷远处? 输入 第一行是一个整数T,表示测试数据的组数. 每组测试数据

hihocoder 1513 小Hi的烦恼——bitset

题目:http://hihocoder.com/problemset/problem/1513 自带的题解写得很好-- #include<cstdio> #include<cstring> #include<algorithm> #include<bitset> using namespace std; int rdn() { int ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0')

自己实现的依赖注入小玩具

package app10e.util; import javax.sql.DataSource; import com.mchange.v2.c3p0.ComboPooledDataSource; import com.mchange.v2.c3p0.DataSources; import app10d.action.GetProductsAction; import app10d.action.SaveProductAction; import app10d.dao.ProductDAO;