Codeforces 704C - Black Widow(dp)
u1s1 感觉这种题被评到 *2900 是因为细节太繁琐了,而不是题目本身的难度,所以我切掉这种题根本不能说明什么……
首先题目中有一个非常喜闻乐见的条件那就是 \(k_i\le 2\),因此我们考虑将每个布尔型变量看作一个点,对于出现在同一组的两个布尔型变量 \(x,y\) 连边 \((x,y)\),那么显然得到的图一定是一堆环、一堆链以及一堆孤立点。
考虑对于每个环及每个链分别跑一遍 DP。对于链我们就设 \(dp_{i,j,k}\) 表示考虑到链上第 \(i\) 个点,第 \(i\) 个点对应的布尔变量的取值为 \(j\),当前所有布尔表达式的值异或起来为 \(k\) 的方案数,转移就枚举上一个布尔变量的值即可。对于环我们就多开一维 \(dp_{i,j,k,fst}\),\(fst\) 表示环上第一个数为 \(fst\),然后我们最后就强制从 \(j=fst\) 的 \(dp\) 计算答案即可。最后再套一个大背包,\(f_{i,j}\) 表示考虑到前 \(i\) 个连通块(环+链),这些连通块中所有表达式异或起来为 \(j\) 的方案数,这个同样可以 \(\mathcal O(1)\) 转移,总复杂度线性。
程序大致框架就这么多,不过此题细节实在是太太太多了,如果能 1A 就真的是神仙了,这里列出几个容易犯的错误:
- 对于 \(x_i\lor\lnot x_i\) 的表达式,不论 \(x_i\) 取什么该表达式的值都是 \(1\),我们考虑随时维护一个 \(goal\) 变量表示我们最终希望所有布尔表达式异或起来是多少,初始 \(goal=1\),我们每遇到一个这样的表达式都令 \(goal\leftarrow goal\oplus 1\),最终输出 \(f_{\text{连通块个数},goal}\) instead of \(f_{\text{连通块个数},1}\) 即可。
- 对于 \(x_i\lor x_i\) 或者 \(\lnot x_i\lor\lnot x_i\) 的表达式,显然其等效于一个孤立点。对于每个孤立点,我们也可以将其看作一个连通块,\(f_{i,0}=f_{i,1}=f_{i-1,0}+f_{i-1,1}\),其中 \(i\) 为该孤立点对应的连通块的编号。
- 对于单一变量的布尔表达式,我们记录一个 \(msk_i\),取值范围 \(\{-1,0,1\}\),\(msk_i=-1\) 表示 \(i\) 以 \(\lnot x_i\) 的形式计入答案,\(msk_i=1\) 表示 \(i\) 以 \(x_i\) 的形式计入答案,\(msk_i=0\) 表示 \(i\) 不计入答案。显然我们每遇到一个单一变量的布尔表达式都可以 \(\mathcal O(1)\) 更新 \(msk_i\)。最后对于所有对于图上的孤立点,若 \(msk_i=\pm 1\),则我们可将其视作一个连通块,\(f_{i,0}=f_{i,1}=f_{i-1,0}+f_{i-1,1}\)。否则你这个变量爱取 \(1\) 就取 \(1\),爱取 \(0\) 就取 \(0\),对异或值没有任何影响,答案乘 \(2\)。
- 对于每条链,若其端点以单一变量的形式计入答案,即 \(msk_i\ne 0\),以 \(msk_i=1\) 为例,那么我们就在 \(dp\) 时候令 \(dp\) 初值为 \(dp_{0,x_i,x_i}=1\) instead of \(dp_{0,x_i,0}=1\) 即可;\(msk_i=-1\) 就令 \(dp_{0,x_i,\lnot x_i}=1\)。结尾处也同理,就在根据结尾处的 \(dp\) 值转移 \(f_{i,j}\) 时稍微改几个细节即可。
总而言之是一道阿巴细节题。
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MAXN=1e5;
const int MOD=1e9+7;
void add(int &x,int y){x+=y;if(x>=MOD) x-=MOD;}
int n,m,msk[MAXN+5],deg[MAXN+5];bool vis[MAXN+5];
int sgn(int x){return (x>0)?0:1;}
struct edge{
int u,v,su,sv,id;
edge(int _u,int _v,int _su,int _sv,int _id):u(_u),v(_v),su(_su),sv(_sv),id(_id){}
};
vector<edge> g[MAXN+5];
int f[MAXN+5][2];
vector<pair<int,pii> > ch;
void dfs(int x,int pre,int rt){
vis[x]=1;
for(int i=0;i<g[x].size();i++){
int y=g[x][i].v,sx=g[x][i].su,sy=g[x][i].sv,id=g[x][i].id;
if(id==pre) continue;ch.pb(mp(y,mp(sx,sy)));
if(y^rt){dfs(y,id,rt);return;}
}
}
int main(){
scanf("%d%d",&m,&n);int goal=1;
memset(msk,-1,sizeof(msk));int mul=1;
f[0][0]=1;int grp_n=0;
for(int i=1;i<=m;i++){
int k;scanf("%d",&k);
if(k==1){
int x;scanf("%d",&x);
if(!~msk[abs(x)]) msk[abs(x)]=sgn(x);
else{
if(msk[abs(x)]^sgn(x)) goal^=1;
msk[abs(x)]=-1;
}
} else {
int u,v;scanf("%d%d",&u,&v);
if(u==v){
vis[abs(u)]=1;grp_n++;
f[grp_n][0]=f[grp_n][1]=(f[grp_n-1][0]+f[grp_n-1][1])%MOD;
} else if(u+v==0) goal^=1,vis[abs(u)]=1,mul=2ll*mul%MOD;
else if(u+v!=0){
g[abs(u)].pb(edge(abs(u),abs(v),sgn(u),sgn(v),i));
g[abs(v)].pb(edge(abs(v),abs(u),sgn(v),sgn(u),i));
deg[abs(u)]++;deg[abs(v)]++;
}
}
}
for(int i=1;i<=n;i++){
if(!deg[i]){
if(!~msk[i]&&!vis[i]) mul=2ll*mul%MOD;
else if(!vis[i]){
grp_n++;
f[grp_n][0]=f[grp_n][1]=(f[grp_n-1][0]+f[grp_n-1][1])%MOD;
}
} else if(deg[i]==1&&!vis[i]){
ch.clear();ch.pb(mp(i,mp(0,0)));dfs(i,0,0);vector<int> dp[2][2];
for(int j=0;j<2;j++) for(int k=0;k<2;k++) dp[j][k].resize(ch.size());
if(~msk[i]) for(int j=0;j<2;j++) dp[j][j^msk[i]][0]=1;
else for(int j=0;j<2;j++) dp[j][0][0]=1;
for(int j=1;j<ch.size();j++){
int su=ch[j].se.fi,sv=ch[j].se.se;
for(int o=0;o<2;o++) for(int p=0;p<2;p++) for(int q=0;q<2;q++){
add(dp[o][((p^su)|(o^sv))^q][j],dp[p][q][j-1]);
}
} grp_n++;int lst=ch.back().fi;
for(int o=0;o<2;o++) for(int p=0;p<2;p++){
int res=o;if(~msk[lst]) res^=(p^msk[lst]);
add(f[grp_n][0],1ll*f[grp_n-1][res]*dp[p][o].back()%MOD);
add(f[grp_n][1],1ll*f[grp_n-1][res^1]*dp[p][o].back()%MOD);
}
// printf("Group %d:\n",grp_n);
// for(int j=0;j<ch.size();j++) printf("%d %d %d\n",ch[j].fi,ch[j].se.fi,ch[j].se.se);
// for(int j=0;j<ch.size();j++) printf("%d %d %d %d\n",dp[0][0][j],dp[0][1][j],dp[1][0][j],dp[1][1][j]);
// printf("%d %d %d\n",i,f[grp_n][0],f[grp_n][1]);
}
}
for(int i=1;i<=n;i++) if(deg[i]==2&&!vis[i]){
ch.clear();ch.pb(mp(i,mp(0,0)));dfs(i,0,i);vector<int> dp[2][2][2];
for(int j=0;j<2;j++) for(int k=0;k<2;k++) for(int l=0;l<2;l++) dp[j][k][l].resize(ch.size());
for(int j=0;j<2;j++) dp[j][0][j][0]=1;
for(int j=1;j<ch.size();j++){
int su=ch[j].se.fi,sv=ch[j].se.se;
for(int o=0;o<2;o++) for(int p=0;p<2;p++)
for(int q=0;q<2;q++) for(int r=0;r<2;r++){
add(dp[o][((p^su)|(o^sv))^q][r][j],dp[p][q][r][j-1]);
}
} grp_n++;int lst=ch.back().fi;
for(int o=0;o<2;o++) for(int p=0;p<2;p++){
add(f[grp_n][0],1ll*f[grp_n-1][o]*dp[p][o][p].back()%MOD);
add(f[grp_n][1],1ll*f[grp_n-1][o^1]*dp[p][o][p].back()%MOD);
}
// printf("Group %d:\n",grp_n);
// for(int j=0;j<ch.size();j++) printf("%d %d %d\n",ch[j].fi,ch[j].se.fi,ch[j].se.se);
// printf("%d %d %d\n",i,f[grp_n][0],f[grp_n][1]);
}
printf("%d\n",1ll*f[grp_n][goal]*mul%MOD);
return 0;
}
/*
8 10
1 -5
2 4 -6
2 -2 -6
2 -7 9
2 10 -1
2 3 -1
2 -8 9
2 5 8
*/
Codeforces 704C - Black Widow(dp)的更多相关文章
- Codeforces Gym101341K:Competitions(DP)
http://codeforces.com/gym/101341/problem/K 题意:给出n个区间,每个区间有一个l, r, w,代表区间左端点右端点和区间的权值,现在可以选取一些区间,要求选择 ...
- codeforces 711C Coloring Trees(DP)
题目链接:http://codeforces.com/problemset/problem/711/C O(n^4)的复杂度,以为会超时的 思路:dp[i][j][k]表示第i棵数用颜色k涂完后bea ...
- codeforces#1154F. Shovels Shop (dp)
题目链接: http://codeforces.com/contest/1154/problem/F 题意: 有$n$个物品,$m$条优惠 每个优惠的格式是,买$x_i$个物品,最便宜的$y_i$个物 ...
- Codeforces 1051 D.Bicolorings(DP)
Codeforces 1051 D.Bicolorings 题意:一个2×n的方格纸,用黑白给格子涂色,要求分出k个连通块,求方案数. 思路:用0,1表示黑白,则第i列可以涂00,01,10,11,( ...
- Codeforces 1207C Gas Pipeline (dp)
题目链接:http://codeforces.com/problemset/problem/1207/C 题目大意是给一条道路修管道,相隔一个单位的管道有两个柱子支撑,管道柱子高度可以是1可以是2,道 ...
- Codeforces 682B New Skateboard(DP)
题目大概说给一个数字组成的字符串问有几个子串其代表的数字(可以有前导0)能被4整除. dp[i][m]表示字符串0...i中mod 4为m的后缀的个数 通过在i-1添加str[i]字符转移,或者以st ...
- Codeforces 543D Road Improvement(DP)
题目链接 Solution 比较明显的树形DP模型. 首先可以先用一次DFS求出以1为根时,sum[i](以i为子树的根时,满足要求的子树的个数). 考虑将根从i变换到它的儿子j时,sum[i]产生的 ...
- Codeforces 543C Remembering Strings(DP)
题意比较麻烦 见题目链接 Solution: 非常值得注意的一点是题目给出的范围只有20,而众所周知字母表里有26个字母.于是显然对一个字母进行变换后是不影响到其它字符串的. 20的范围恰好又是常见状 ...
- codeforces#983 B. XOR-pyramid (dp)
参考博客:https://www.01hai.com/note/av137952. 题意:首先定义 (b代表一个数组) 给出一个区间,l,r,求它最大的连续子序列的函数值 分析: 定义dp[x][y] ...
随机推荐
- 在hive中使用COALESCE进行空值处理
COALESCE (expression_1, expression_2, ...,expression_n)依次参考各参数表达式,遇到非null值即停止并返回该值.如果所有的表达式都是空值,最终将返 ...
- 在 ASP.NET Core Web API中使用 Polly 构建弹性容错的微服务
在 ASP.NET Core Web API中使用 Polly 构建弹性容错的微服务 https://procodeguide.com/programming/polly-in-aspnet-core ...
- ffmpeg剪视频
ffmpeg裁剪合并视频 ffmpeg提供简单的命令参数: ffmpeg -ss START -t DURATION -i INPUT -vcodec copy -acodec copy OUTP ...
- stm32电机控制之控制两路直流电机
小车使用的电机是12v供电的直流电机,带编码器反馈,这样就可以采用闭环速度控制,这里电机使用PWM驱动,速度控制框图如下: 由以上框图可知,STM32通过定时器模块输出PWM波来控制两个直流电机的转动 ...
- 如何优雅的处理 accept 出现 EMFILE 的问题
通常情况下,服务端调用 accept 函数会返回一个新的文件描述符,用于和客户端之间的数据传输 在服务器的开发中,有时会遇到这种情况:当调用 accept 函数接受客户端连接,函数返回失败,对应的错误 ...
- tar 解压分割压缩文件
被分割后的压缩文件必须先合并成一个压缩文件才能正常的解压. 第一步.合并压缩文件 第二步.正常解压 $ls TINA-1.3.tar.gzaa TINA-1.3.tar.gzab TINA-1.3.t ...
- AXI协议中的模棱两可的含义的解释(Cachable和Bufferable)
转载:https://blog.csdn.net/hit_shaoqi/article/details/53243173 Cachable和Bufferable 一个Master发出一个读写的requ ...
- hdu 3038 How Many Answers Are Wrong(并查集)
题意: N和M.有N个数. M个回答:ai, bi, si.代表:sum(ai...bi)=si.如果这个回答和之前的冲突,则这个回答是假的. 问:M个回答中有几个是错误的. 思路: 如果知道sum( ...
- Spring Cloud Alibaba环境搭建
前言:Spring Cloud Alibaba是目前主流的分布式微服务架构,本文主要讲解了在IDEA中如何搭建Spring Cloud Alibaba环境,以及介绍Spring Cloud Aliba ...
- MarkDown学习随笔
MarkDown语法的学习 标题 设置标题方法是在前面加#号,一级标题(最大)是加#+空格 ,二级标题是加##+空格,之后的以此类推. 字体 在文本的前后分别加上一个星号表示斜体字 在文本的前后分 ...