Codeforces 题目传送门 & 洛谷题目传送门

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)的更多相关文章

  1. Codeforces Gym101341K:Competitions(DP)

    http://codeforces.com/gym/101341/problem/K 题意:给出n个区间,每个区间有一个l, r, w,代表区间左端点右端点和区间的权值,现在可以选取一些区间,要求选择 ...

  2. codeforces 711C Coloring Trees(DP)

    题目链接:http://codeforces.com/problemset/problem/711/C O(n^4)的复杂度,以为会超时的 思路:dp[i][j][k]表示第i棵数用颜色k涂完后bea ...

  3. codeforces#1154F. Shovels Shop (dp)

    题目链接: http://codeforces.com/contest/1154/problem/F 题意: 有$n$个物品,$m$条优惠 每个优惠的格式是,买$x_i$个物品,最便宜的$y_i$个物 ...

  4. Codeforces 1051 D.Bicolorings(DP)

    Codeforces 1051 D.Bicolorings 题意:一个2×n的方格纸,用黑白给格子涂色,要求分出k个连通块,求方案数. 思路:用0,1表示黑白,则第i列可以涂00,01,10,11,( ...

  5. Codeforces 1207C Gas Pipeline (dp)

    题目链接:http://codeforces.com/problemset/problem/1207/C 题目大意是给一条道路修管道,相隔一个单位的管道有两个柱子支撑,管道柱子高度可以是1可以是2,道 ...

  6. Codeforces 682B New Skateboard(DP)

    题目大概说给一个数字组成的字符串问有几个子串其代表的数字(可以有前导0)能被4整除. dp[i][m]表示字符串0...i中mod 4为m的后缀的个数 通过在i-1添加str[i]字符转移,或者以st ...

  7. Codeforces 543D Road Improvement(DP)

    题目链接 Solution 比较明显的树形DP模型. 首先可以先用一次DFS求出以1为根时,sum[i](以i为子树的根时,满足要求的子树的个数). 考虑将根从i变换到它的儿子j时,sum[i]产生的 ...

  8. Codeforces 543C Remembering Strings(DP)

    题意比较麻烦 见题目链接 Solution: 非常值得注意的一点是题目给出的范围只有20,而众所周知字母表里有26个字母.于是显然对一个字母进行变换后是不影响到其它字符串的. 20的范围恰好又是常见状 ...

  9. codeforces#983 B. XOR-pyramid (dp)

    参考博客:https://www.01hai.com/note/av137952. 题意:首先定义 (b代表一个数组) 给出一个区间,l,r,求它最大的连续子序列的函数值 分析: 定义dp[x][y] ...

随机推荐

  1. Salesforce 生命周期管理(二)Agile & Scrum 浅谈

    本篇参考: https://trailhead.salesforce.com/content/learn/modules/salesforce-agile-basics https://www.scr ...

  2. 改善深层神经网络-week1编程题(Initializaion)

    Initialization 如何选择初始化方式,不同的初始化会导致不同的结果 好的初始化方式: 加速梯度下降的收敛(Speed up the convergence of gradient desc ...

  3. CentOS系统优化一键配置脚本

    #!/usr/bin/env bash PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export P ...

  4. stm32f103系列引脚定义-功能图

    器件功能和配置(STM32F103xx增强型) STM32F103xx增强型模块框架图 STM32F103xx增强型VFQFPN36管脚图 STM32F103xx增强型LQFP100管脚图 STM32 ...

  5. 洛谷 P5664 [CSP-S2019] Emiya 家今天的饭

    链接: P5664 题意: 给出一个 \(n*m\) 的矩阵 \(a\),选 \(k\) 个格子(\(1\leq k\leq n\)),每行最多选一个,每列最多选\(⌊\dfrac k2⌋\) 个,同 ...

  6. python mysqlclient安装失败 Command "python setup.py egg_info" failed with error code 1

    python2 python3 中代码 pip install mysqlclient 都安装失败的话, 很有可能是你的操作系统中没有安装mysql 如果确定已经安装了,请忽略下面的内容. Ubunt ...

  7. Oracle 19c 单机

    环境 vm虚拟机 双磁盘 操作系统 Oracle Linux 7.9 操作系统安装带图形 选择中文,注意不要新建用户 关闭防火墙 selinux 配置好IP 挂载系统盘镜像 修改主机名 配置hosts ...

  8. WLAN-无线路由综合应用

    一.实验目的 掌握综合应用的配置 二.实验仪器设备及软件 实验仪器设备:路由器.三层交换机.3台二层交换机.AC.3台AP 软件:ensp   三.实验原理   四.实验内容与步骤 AC配置: [AC ...

  9. LOTO虚拟示波器软件功能演示之——FIR数字滤波

    本文章介绍一下LOTO示波器新出的功能--FIR数字滤波的功能. 在此之前我们先来了解一下带通滤波和带阻滤波.我们都知道每个信号是不同频率不同幅值正弦波的线性叠加,为了方便直接得观察到这种现象,就有了 ...

  10. Fiddler抓包工具学习及使用

    一.Fiddler工作原理 Fiddler是位于客户端和服务器端之间的代理,客户端发送请求,fiddler会拦截该请求,再转发到服务器端,服务器端处理请求做出的响应,也要被fiddler拦截,fidd ...