【题目】C. Black Widow

【题意】给定一个表达式,形式为(...)^(...)^......^(...)=1(n个括号),括号中为1~2个值取或。有m个变量,给出表达式的值为xi或 !xi,xi只能为0或1,求变量赋值使得表达式成立的方案数。每个变量至多出现两次。n,m<=10^5。

【算法】动态规划+模拟

【题解】每个括号视为一个点,对于同时出现在两个括号内的变量将两个点连边(边须记两边异同)。由于每个变量至多出现两次,所以一条边就可以代表一个变量。

由于每个括号至多两个变量,所以整个图是若干独立的链或环。

对于链:f[i][j][k]表示考虑到第i条边,当前边取值j=0或1,当前全局取值k=0或1的方案数。

从链的一端开始考虑,到链的另一端结束。

对于环:先决定好第一条边的取值,然后像链一样做即可。

最后将若干子图用简单的DP或组合数计算出最终答案。

复杂度O(n)。

实际操作过程相当复杂,请务必小心食用本题……QAQ

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;
int read(){
char c;int s=,t=;
while(!isdigit(c=getchar()))if(c=='-')t=-;
do{s=s*+c-'';}while(isdigit(c=getchar()));
return s*t;
}
const int maxn=,MOD=1e9+;
int f[maxn][][],dp[][],tot=,first[maxn],in[maxn],ans[maxn][],cnt,fir;
int n,m,c[maxn][],d[maxn][],uv,uuv,vv,be,fr,p[maxn];
bool vis[maxn];
struct edge{int v,w,from;}e[maxn*];
void insert(int u,int v,int w){tot++;e[tot].v=v;e[tot].w=w;e[tot].from=first[u];first[u]=tot;in[v]++;}
int M(int x){return x>=MOD?x-MOD:x;}
void dfs(int x,int fa,int w){
bool ok=;vis[x]=;
f[x][][]=M(f[fa][][w]+f[fa][][w^]);
f[x][][]=M(f[fa][][]+f[fa][][]);
f[x][][]=M(f[fa][][w^]+f[fa][][w]);
f[x][][]=M(f[fa][][]+f[fa][][]);
for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa){
ok=;
dfs(e[i].v,x,e[i].w);
}
if(ok){ ans[cnt][]=M(ans[cnt][]+M(f[x][][]+(p[x]?:f[x][][])));
ans[cnt][]=M(ans[cnt][]+M(f[x][][]+(p[x]?:f[x][][])));
}
}
void round(int x,int fa,int w,int b){
vis[x]=;
f[x][][]=M(f[fa][][w]+f[fa][][w^]);
f[x][][]=M(f[fa][][]+f[fa][][]);
f[x][][]=M(f[fa][][w^]+f[fa][][w]);
f[x][][]=M(f[fa][][]+f[fa][][]);
for(int i=first[x];i;i=e[i].from)if(i!=fr&&(i^)!=b){
if(e[i].v!=be)round(e[i].v,x,e[i].w,i);
else{
if(!fir){
ans[cnt][]=M(f[x][e[i].w^][]+f[x][e[i].w][]);
ans[cnt][]=M(f[x][e[i].w][]+f[x][e[i].w^][]);
}
else{
ans[cnt][]=M(ans[cnt][]+M(f[x][][]+f[x][][]));
ans[cnt][]=M(ans[cnt][]+M(f[x][][]+f[x][][]));
}
}
}
}
int main(){
n=read();m=read();
for(int i=;i<=n;i++){
int k=read();if(k==)p[i]=;
for(int j=;j<=k;j++){
int x=read();
if(x<)c[-x][++c[-x][]]=i,d[-x][c[-x][]]=;
else c[x][++c[x][]]=i;
}
}
for(int i=;i<=m;i++){
if(c[i][]==)uv++;
if(c[i][]==){
if(c[i][]==c[i][]){p[c[i][]]=;if(d[i][]==d[i][])uuv++;else vv++;continue;}
insert(c[i][],c[i][],d[i][]^d[i][]);
insert(c[i][],c[i][],d[i][]^d[i][]);
}
}
for(int i=;i<=n;i++)if(!vis[i]&&in[i]==){
cnt++;
f[][][]=;
dfs(i,,);
if(!p[i]){
dfs(i,,);
}
f[][][]=;
}
for(int i=;i<=n;i++)if(!vis[i]&&in[i]==){
cnt++;
f[i][][]=;fir=;be=i;vis[i]=;fr=e[first[i]].from;
round(e[first[i]].v,i,e[first[i]].w,first[i]);
f[i][][]=;f[i][][]=;fir=;
round(e[first[i]].v,i,e[first[i]].w,first[i]);
}
for(int i=;i<=n;i++)if(!vis[i]&&in[i]==&&p[i]!=){cnt++;ans[cnt][]=;ans[cnt][]=p[i]?:;}
int x=;
dp[x][vv&]=;
for(int i=;i<=vv;i++)dp[x][vv&]=dp[x][vv&]*%MOD;
for(int i=;i<=uuv;i++){
x=-x;
dp[x][]=M(dp[-x][]+dp[-x][]);
dp[x][]=M(dp[-x][]+dp[-x][]);
}
for(int i=;i<=cnt;i++){
x=-x;
dp[x][]=(1ll*ans[i][]*dp[-x][]+1ll*ans[i][]*dp[-x][])%MOD;
dp[x][]=(1ll*ans[i][]*dp[-x][]+1ll*ans[i][]*dp[-x][])%MOD;
}
for(int i=;i<=uv;i++)dp[x][]=dp[x][]*%MOD;
printf("%d",dp[x][]);
return ;
}

【CodeForces】704 C. Black Widow 动态规划+模拟的更多相关文章

  1. codeforces 723B Text Document Analysis(字符串模拟,)

    题目链接:http://codeforces.com/problemset/problem/723/B 题目大意: 输入n,给出n个字符的字符串,字符串由 英文字母(大小写都包括). 下划线'_' . ...

  2. Codeforces Round #304 C(Div. 2)(模拟)

    题目链接: http://codeforces.com/problemset/problem/546/C 题意: 总共有n张牌,1手中有k1张分别为:x1, x2, x3, ..xk1,2手中有k2张 ...

  3. Codeforces 749C:Voting(暴力模拟)

    http://codeforces.com/problemset/problem/749/C 题意:有n个人投票,分为 D 和 R 两派,从1~n的顺序投票,轮到某人投票的时候,他可以将对方的一个人K ...

  4. Educational Codeforces Round 2 A. Extract Numbers 模拟题

    A. Extract Numbers Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/600/pr ...

  5. Codeforces 716B Complete the Word【模拟】 (Codeforces Round #372 (Div. 2))

    B. Complete the Word time limit per test 2 seconds memory limit per test 256 megabytes input standar ...

  6. CodeForces 797C Minimal string:贪心+模拟

    题目链接:http://codeforces.com/problemset/problem/797/C 题意: 给你一个非空字符串s,空字符串t和u.有两种操作:(1)把s的首字符取出并添加到t的末尾 ...

  7. Codeforces 37D Lesson Timetable - 组合数学 - 动态规划

    题目传送门 神奇的门I 神奇的门II 题目大意 有$n$组学生要上课2次课,有$m$个教室,编号为$1$到$m$.要确定有多少种不同的安排上课的教室的方案(每组学生都是本质不同的),使得它们满足: 每 ...

  8. Codeforces Beta Round #3 C. Tic-tac-toe 模拟题

    C. Tic-tac-toe 题目连接: http://www.codeforces.com/contest/3/problem/C Description Certainly, everyone i ...

  9. Codeforces Beta Round #1 B. Spreadsheets 模拟

    B. Spreadsheets 题目连接: http://www.codeforces.com/contest/1/problem/B Description In the popular sprea ...

随机推荐

  1. lintcode-24-LFU缓存

    24-LFU缓存 LFU是一个著名的缓存算法 实现LFU中的set 和 get 样例 capacity = 3 set(2,2) set(1,1) get(2) >> 2 get(1) & ...

  2. CentOS系统iptables防火墙的启动、停止以及开启关闭端口的操作

    CentOS 配置防火墙操作实例(启.停.开.闭端口):注:防火墙的基本操作命令:查询防火墙状态:[root@localhost ~]# service   iptables status停止防火墙: ...

  3. google auth

    思路: secret 系统生成的密钥 把密钥分配给某个用户,用户可以把这个密钥加入到app中,app会1min生成一个code: 验证时,根据用户的 secret ,系统生成一个code,再比较用户输 ...

  4. PHP中大括号用法

    Php中"{}"大括号的用法总结 在PHP中,大括号“{}”可以起到如下作用: 1.将多个独立语句合并为一个复合语句,例如 if ... else ...中经常如此使用 2.在变量 ...

  5. Docker 入门 到部署Web 程序- (阿里面试常用的docker命令和优点)

    最近阿里的面试官问我Docker是做什么用的,我记得之前360和美团,京东的都问过,但是一直没时间看,最近有时间了,系统的学习了一下Docker,在此做一下记录,方便各位看官学习交流 一.Docker ...

  6. linux安装py3.6

    随手记录: https://www.python.org/ftp/python/3.6.8/Python-3.6.8rc1.tgz 所有linux版本: https://www.python.org/ ...

  7. break,continue,return 的区别

    (1)break 跳出当前循环体 (2)continue 跳过当前循环体continue后面的代码,继续执行下一个循环 (3)return 和循环没关系,就是跳出该函数

  8. 【C++】构造函数不能是虚函数

    1 虚函数对应一个vtable,这大家都知道,可是这个vtable其实是存储在对象的内存空间的.问题出来了,如果构造函数是虚的,就需要通过 vtable来调用,可是对象还没有实例化,也就是内存空间还没 ...

  9. Eclipse 保存代码时,不自动换行设置

    Eclipse在保存代码时,总是自动换行.尤其是注释,换行后的注释读起来就很混乱.后来发现是在保存文件时设置了自动格式化代码的原因. 关闭自动格式代码设置: windows-->Preferen ...

  10. week1day01 认识python 变量 数据类型 条件if语句

    1.什么是python? Python是一种解释型.面向对象.动态数据类型的高级程序设计语言.Python由Guido van Rossum于1989年底发明,第一个公开发行版发行于1991年.像Pe ...