HZOJ 巨神兵
60pts:
每个DAG的拓扑序是唯一的,所以考虑将DAG分层。f[i][j]记录当前选择的节点状态是i,最后一层的节点状态为j(dep取最大)。
初始状态:$f[i][i]=1;i\in [1,1<<n)$。那么我们第一层枚举当前状态i,第二层枚举[1,1<<n)。那么令s=i&j,t=j&(~i),s即为i的一个子集,所以令s为当前的最后一层,t为i
的补集的一个子集,令t为转移后的最后一层,要求s到t中每个点都有边。枚举t中每个点,设ch1为集合$i-s$当前点的边数,ch2为s集合到当前点的边数,转移方程:$f[i$|$t][t]+=f[i][s]*\prod 2^{ch1}*\prod (2^{ch2}-1)$;
#include<iostream>
#include<cstring>
#include<cstdio>
#include<bitset>
#include<vector>
#define LL long long
using namespace std;
const int mod=1e9+;
struct edge
{
int u,v,nxt;
#define u(x) ed[x].u
#define v(x) ed[x].v
#define n(x) ed[x].nxt
}ed[];
int first[],num_e;
#define f(x) first[x]
int n,m,ru[];
LL f[<<][<<];
vector<int> fr[];
bool pd(int s,int t)
{
bool ok=;
for(int i=;i<=n;i++)
if((<<i-)&t)
{
bool pd2=;
for(int j=;j<fr[i].size();j++)
if((<<fr[i][j]-)&s)pd2=;
ok&=pd2;
}
return ok;
}
LL find(int s,int po)
{
int res=;
for(int i=;i<fr[po].size();i++)
if((<<fr[po][i]-)&s)res++;
return res;
}
LL poww(LL a,int b);
inline void add(int u,int v);
signed main()
{
cin>>n>>m;int tu,tv;
for(int i=;i<=m;i++)cin>>tu>>tv,add(tu,tv),ru[tv]++,fr[tv].push_back(tu); for(int i=;i<(<<n);i++)f[i][i]=;
for(int i=;i<(<<n);i++)
{
for(int j=;j<(<<n);j++)
{
int s=i&j,t=j&(~i);
bitset<>t1(i),t2(s),t3(t);
// cout<<t1<<" "<<t2<<" "<<(t1|t3)<<" "<<t3<<endl;
if(s&&t&&pd(s,t))
{
int ch1=,ch2=;
for(int k=;k<=n;k++)
if((<<k-)&t)
{
int cnt1=find(i&(~s),k),cnt2=find(s,k);
ch1=ch1*poww(,cnt1)%mod;ch2=ch2*(poww(,cnt2)-)%mod;
}
f[i|t][t]=((f[i|t][t]+f[i][s]*ch1*ch2)%mod)%mod;
}
// cout<<f[i][s]<<" -> "<<f[i|t][t]<<endl;
}
}
LL ans=;
// for(int i=1;i<(1<<n);i++)
for(int j=;j<(<<n);j++)
ans=(ans+f[(<<n)-][j])%mod;
printf("%lld\n",ans);
}
inline void add(int u,int v)
{
++num_e;
u(num_e)=u;
v(num_e)=v;
n(num_e)=f(u);
f(u)=num_e;
}
LL poww(LL a,int b)
{
LL ans=;
while(b)
{
if(b&)ans=ans*a%mod;
a=a*a%mod;b=b>>;
}
return ans;
}
100pts:
考虑将第二维去掉,f[i]表示当前集合为i时的方案数,那么$f[i]=\sum f[i][j]$,如果不记录最后一层的话,每一个j都会被计算进去多次,所以容斥一下就可以了(稍不明白)。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<bitset>
#include<vector>
#define re register
#define co const
#define rec re co
#define LL long long
using namespace std;
const int mod=1e9+;
struct edge
{
int u,v,nxt;
#define u(x) ed[x].u
#define v(x) ed[x].v
#define n(x) ed[x].nxt
}ed[];
int first[],num_e;
#define f(x) first[x]
int n,m,ru[];
LL f[<<],g[<<];
int tem[<<][];
vector<int> fr[];
bool pd(int s,int t)
{
bool ok=;
for(int i=;i<=n;i++)
if((<<i-)&t)
{
bool pd2=;
for(int j=;j<fr[i].size();j++)
if((<<fr[i][j]-)&s)pd2=;
ok&=pd2;
}
return ok;
}
LL find(rec int s,rec int po)
{
int res=;
for(int i=;i<fr[po].size();i++)
if((<<fr[po][i]-)&s)res++;
return res;
}
int pw[];
int siz[<<];
LL poww(LL a,int b);
inline void add(rec int u,rec int v);
signed main()
{
// freopen("obelisk9.in","r",stdin); cin>>n>>m;int tu,tv;
for(re int i=;i<=m;i++)scanf("%d%d",&tu,&tv),add(tu,tv),ru[tv]++,fr[tv].push_back(tu); for(re int i=;i<(<<n);i++){bitset<>t(i);siz[i]=t.count();}
for(re int i=;i<(<<n);i++)for(re int j=;j<=n;j++)tem[i][j]=find(i,j);
f[]=;
pw[]=;for(int i=;i<=;i++)pw[i]=pw[i-]*%mod;
for(int i=;i<=n;i++)g[<<i-]=i;
int tttttt=(<<n);
for(re int i=;i<tttttt;i++)
{
int all=(~i)&(tttttt-);
for(re int k=all;k;k=(k-)&all)
{
int cnt=;
for(re int j=k;j;j-=(j&-j))
cnt+=tem[i][g[j&-j]]; if(siz[k]&)f[i|k]=(f[i|k]+f[i]*pw[cnt]%mod);
else f[i|k]=(f[i|k]-f[i]*pw[cnt]%mod);
if(f[i|k]<)f[i|k]=f[i|k]%mod+mod;
if(f[i|k]>=mod)f[i|k]-=mod;
}
} printf("%lld\n",(f[(<<n)-]%mod+mod)%mod);
}
inline void add(rec int u,rec int v)
{
++num_e;
u(num_e)=u;
v(num_e)=v;
n(num_e)=f(u);
f(u)=num_e;
}
LL poww(LL a,int b)
{
LL ans=;
while(b)
{
if(b&)ans=ans*a%mod;
a=a*a%mod;b=b>>;
}
return ans;
}
HZOJ 巨神兵的更多相关文章
- BZOJ 3812 主旋律 (状压DP+容斥) + NOIP模拟赛 巨神兵(obelisk)(状压DP)
这道题跟另一道题很像,先看看那道题吧 巨神兵(obelisk) 题面 欧贝利斯克的巨神兵很喜欢有向图,有一天他找到了一张nnn个点mmm条边的有向图.欧贝利斯克认为一个没有环的有向图是优美的,请问这张 ...
- [CSP-S模拟测试]:巨神兵(状压DP)
题目描述 欧贝利斯克的巨神兵很喜欢有向图,有一天他找到了一张$n$个点$m$条边的有向图.欧贝利斯克认为一个没有环的有向图是优美的,请问这张图有多少个子图(即选定一个边集)是优美的?答案对$1,000 ...
- csp-s模拟测试57(10.2)「天空龙」·「巨神兵」·「太阳神」
题目是古埃及神话??? A. 天空龙 傻逼模拟,看来没有滑天下之大稽QAQ,也没有打错快读(大雾...) B. 巨神兵 难度爆增,一脸懵比..... 60分状压: 因为是求有向图,关于有向图好像拓扑用 ...
- hzoj 2301(莫比乌斯反演)
题意 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公 数. 思路: 与先前的那个相比,这次a,c并不一定 ...
- NOIp模拟赛 巨神兵(状压DP 容斥)
\(Description\) 给定\(n\)个点\(m\)条边的有向图,求有多少个边集的子集,构成的图没有环. \(n\leq17\). \(Solution\) 问题也等价于,用不同的边集构造DA ...
- 【2016NOIP十连测】【test4】【状压DP】【容斥原理】巨神兵
题目大意: 给一个n个点(n<=17),m条边的有向图(无自环.无重边),求其无环子图的方案数. 题解: 看到n<=17,显然是用状压dp. 用f[i]表示点集i的满足条件的方案数. 状态 ...
- HZOJ 单
两个子任务真的是坑……考试的时候想到了60分的算法,然而只拿到了20分(各种沙雕错,没救了……). 算法1: 对于测试点1,直接n遍dfs即可求出答案,复杂度O(n^2),然而还是有好多同学跑LCA/ ...
- 20191102 「HZOJ NOIP2019 Round #12」20191102模拟
先开坑. md原题写挂我也真是... 100+20+10 白夜 打表大法吼 显然,不在环上的点对答案的贡献是 \((k-cycle)^{k-1}\) . 打表得到环上的递推式,矩阵一下乘起来就好了. ...
- 20191004 「HZOJ NOIP2019 Round #9」20191004模拟
综述 第一次 rk1 ,激动. 题目是 COCI 18/19 Round #1 的三至五题. 得分 \(100+100+20\) \(\mathrm{cipele}\) 问题描述 HZOJ1313 题 ...
随机推荐
- Redis使用:聚合类型为空时,会自动被Redis删除
项目中使用Redis来记录用户的上线和下线信息,其中用到了集合(sets)类型,某用户上线时,向sets中添加数据,下线时将相应数据从sets中删除,考虑当该用户的所有实例都下线时,需要将sets删除 ...
- a标签实现 批量下载
// 批量下载 download (name, href) { var a = document.createElement('a') var e = document.createEvent('Mo ...
- TZ_05_Spring_annotation常见注解
Spring常用的注解大全和解释 注解 解释 @Controller 组合注解(组合了@Component注解),应用在MVC层(控制层),DispatcherServlet会自动扫描注解了此注解的类 ...
- php 该如何获取从百度搜索进入网站的关键词
清源分享一个php获取从百度搜索进入网站的关键词的代码,有需要的朋友可以参考一下:https://blog.csdn.net/u012275531/article/details/17609065 代 ...
- spring cloud深入学习(一)-----什么是微服务?什么是rpc?spring cloud简介
近年来,微服务非常的流行,那么为什么是它?简单介绍一下. 为什么是微服务? 微服务架构是一种将单应用程序作为一套小型服务开发的方法,每种应用程序都在其自己的进程中运行,并与轻量级机制(通常是HTTP资 ...
- 【arc077f】AtCoder Regular Contest 074 F - Lotus Leaves
题意 给定一个n*m的池塘,每个格子上可能有叶子. 从一个叶子出发,可以跳到相同行或相同列的叶子. 问至少去掉多少叶子,使得起点不能到达终点. \(n,m<=100\) 解法 很显然的最小割模型 ...
- mysql向某个字段前边追加一个字符串CONCAT命令
比如,我在处理图片的时候把https写成了tps 那我就要补全 UPDATE t_article set imgs=CONCAT('ht',imgs);
- 洛谷P1072 [NOIP2009] Hankson 的趣味题
P1072 Hankson 的趣味题 题目描述 Hanks 博士是 BT (Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫 Hankson.现在,刚刚放学回家的 Hankson 正在思考一 ...
- 【洛谷】P1880 石子合并
P1880 石子合并 题目描述 在一个园形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分. 试设计出1个算法,计 ...
- Leetcode63.Unique Paths II不同路径2
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为"Start" ). 机器人每次只能向下或者向右移动一步.机器人试图达到网格的右下角(在下图中标记为" ...