好题 np.

对于20分 显然可以爆搜。

对于50分 可以发现每个字符串上的问号要么是0,要么是1.考虑枚举一个字符串当前是0还是1 这会和其他字符串产生矛盾。

所以容易 发现这是一个2-sat问题。

拆点 把任意两个产生矛盾的字符串进行连边。然后最后判矛盾即可。

n^2枚举 建图 判断矛盾时使用字符串hash 要分类讨论4种情况。

  1. using namespace std;
  2. const int MAXN=1010,maxn=500010,cc1=19260817,cc2=114514;
  3. int n,mark,cnt,top,id,len;
  4. string a[MAXN];
  5. int flag[MAXN],c[MAXN<<1],low[MAXN<<1],dfn[MAXN<<1],s[MAXN<<1];
  6. int lin[MAXN<<1],ver[MAXN*MAXN<<2],nex[MAXN*MAXN<<2],w[MAXN];
  7. vector<int>h0[MAXN];//表示为0时的前缀hash值 或者表示什么都不是的前缀hash值.
  8. vector<int>h1[MAXN];//表示为1时的前缀hash值
  9. struct wy
  10. {
  11. int len,id;
  12. }t[MAXN];
  13. inline int cmp(wy a,wy b){return a.len<b.len;}
  14. inline void dfs(int x)
  15. {
  16. low[x]=dfn[x]=++cnt;
  17. s[++top]=x;
  18. go(x)
  19. {
  20. if(!dfn[tn])
  21. {
  22. dfs(tn);
  23. low[x]=min(low[x],low[tn]);
  24. }
  25. else if(!c[tn])low[x]=min(low[x],dfn[tn]);
  26. }
  27. if(dfn[x]==low[x])
  28. {
  29. int y=0;++id;
  30. while(y!=x)
  31. {
  32. y=s[top--];
  33. c[y]=id;
  34. }
  35. }
  36. }
  37. inline void add(int x,int y)
  38. {
  39. ver[++len]=y;
  40. nex[len]=lin[x];
  41. lin[x]=len;
  42. }
  43. int main()
  44. {
  45. freopen("code.in","r",stdin);
  46. freopen("code.out","w",stdout);
  47. ios::sync_with_stdio(false);
  48. cin>>n;
  49. if(n<=1000)
  50. {
  51. rep(1,n,i)
  52. {
  53. cin>>a[i];
  54. t[i]=(wy){a[i].size(),i};
  55. }
  56. rep(1,n,i)
  57. {
  58. ll w0=0,w1=0;
  59. rep(0,((int)a[i].size())-1,j)
  60. {
  61. w0=w0*P%mod;
  62. w1=w1*P%mod;
  63. if(a[i][j]=='?')
  64. {
  65. flag[i]=j+1;
  66. w0=(w0+cc1)%mod;
  67. w1=(w1+cc2)%mod;
  68. }
  69. else
  70. {
  71. if(a[i][j]=='0')w1=(w1+cc1)%mod,w0=(w0+cc1)%mod;
  72. else w1=(w1+cc2)%mod,w0=(w0+cc2)%mod;
  73. }
  74. h0[i].pb(w0);
  75. h1[i].pb(w1);
  76. }
  77. }
  78. //x表示这个点选择0 x+n表示这个点选择1.
  79. sort(t+1,t+1+n,cmp);
  80. rep(1,n,i)
  81. {
  82. int x=t[i].id;//x.len<=y.len
  83. int xx=t[i].len;
  84. rep(i+1,n,j)
  85. {
  86. int y=t[j].id;
  87. if(!flag[x]&&(!flag[y]||flag[y]>xx))
  88. {
  89. if(h0[x][xx-1]==h0[y][xx-1])
  90. {
  91. puts("NO");
  92. return 0;
  93. }
  94. continue;
  95. }
  96. if(!flag[x]&&flag[y]<=xx)
  97. {
  98. if(h0[x][xx-1]==h0[y][xx-1])add(y,y+n);
  99. if(h0[x][xx-1]==h1[y][xx-1])add(y+n,y);
  100. continue;
  101. }
  102. if(flag[x]&&(!flag[y]||flag[y]>xx))
  103. {
  104. if(h0[x][xx-1]==h0[y][xx-1])add(x,x+n);
  105. if(h1[x][xx-1]==h0[y][xx-1])add(x+n,x);
  106. }
  107. if(flag[x]&&flag[y]<=xx)
  108. {
  109. if(h0[x][xx-1]==h0[y][xx-1])add(x,y+n),add(y,x+n);
  110. if(h0[x][xx-1]==h1[y][xx-1])add(x,y),add(y+n,x+n);
  111. if(h1[x][xx-1]==h0[y][xx-1])add(x+n,y+n),add(y,x);
  112. if(h1[x][xx-1]==h1[y][xx-1])add(x+n,y),add(y+n,x);
  113. }
  114. }
  115. }
  116. rep(1,n+n,i)if(!dfn[i])dfs(i);
  117. rep(1,n,i)if(c[i]==c[i+n]){puts("NO");return 0;}
  118. puts("YES");
  119. }
  120. return 0;
  121. }

考虑100分。

我考试的时候想了一波trie树 但是当时思考没有在这个暴力的基础上思考 所以 建图也很麻烦 所以弃疗了。

可以发现我们拆过点后 把这些串给放到trie树上。

可以发现连边的时候 使用前缀和连边 即可优化建图了。

对于某个节点存放多个节点 这个时候 对这个节点内部再进行一次前缀和优化建图。

对于某个节点不存在? 考虑子树内和链上上的节点都需要自己向自己的对立连边 这个使用懒标记即可。

上传标记和 标记的时候注意判断不合法的情况。

这个优化建图还是很精髓的。充分的利用了trie树的性质。

注意空间不要开小了 计算不了点数可以开到空间上界小一点。

  1. const int MAXN=500010*3;
  2. int n,sum,cnt=1,top,id,len,last=1,mark;
  3. string a[MAXN];
  4. int t[MAXN][2],ne[MAXN],pos[MAXN];
  5. int flag[MAXN],c[MAXN<<3],low[MAXN<<3],dfn[MAXN<<3],s[MAXN<<3],w1[MAXN],w2[MAXN];
  6. int lin[MAXN<<3],ver[MAXN<<3],nex[MAXN<<3],add1[MAXN],add2[MAXN];
  7. vector<int>g[MAXN];
  8. inline void dfs(int x)
  9. {
  10. low[x]=dfn[x]=++cnt;
  11. s[++top]=x;
  12. go(x)
  13. {
  14. if(!dfn[tn])
  15. {
  16. dfs(tn);
  17. low[x]=min(low[x],low[tn]);
  18. }
  19. else if(!c[tn])low[x]=min(low[x],dfn[tn]);
  20. }
  21. if(dfn[x]==low[x])
  22. {
  23. int y=0;++id;
  24. while(y!=x)
  25. {
  26. y=s[top--];
  27. c[y]=id;
  28. }
  29. }
  30. }
  31. inline void add(int x,int y)
  32. {
  33. ver[++len]=y;
  34. nex[len]=lin[x];
  35. lin[x]=len;
  36. }
  37. inline void insert(int x,int op)
  38. {
  39. int p=1,c=min(x,ne[x]);
  40. for(ui i=0;i<a[c].size();++i)
  41. {
  42. int w=a[c][i]-'0';
  43. if(!t[p][w])t[p][w]=++cnt;
  44. p=t[p][w];
  45. }
  46. if(op)g[p].pb(x);
  47. else
  48. {
  49. if(add1[p])mark=1;
  50. add1[p]=1,add2[p]=1;
  51. }
  52. pos[x]=p;
  53. }
  54. inline void dfs(int x,int fa)
  55. {
  56. int s1=++sum,s2=++sum;
  57. if(w1[fa])add(s1,w1[fa]);//w1[x]表示当前点向前缀所有的点的相反点的连边
  58. if(w2[fa])add(w2[fa],s2);//w2[x]表示前缀所有的点向当前点的连边.
  59. int c1=++sum,c2=++sum,cc1,cc2;//c1表示当前这个点对前缀和的相反点的连边.
  60. //c2表示前缀和的所有点对当前点的连边.
  61. for(ui i=0;i<g[x].size();++i)
  62. {
  63. int tn=g[x][i];
  64. //cout<<tn<<endl;
  65. add(tn,c1);
  66. cc1=++sum;
  67. add(cc1,c1);
  68. add(cc1,ne[tn]);
  69. c1=cc1;
  70. add(c2,ne[tn]);
  71. cc2=++sum;
  72. add(c2,cc2);
  73. add(tn,cc2);
  74. c2=cc2;
  75. if(w1[fa])add(tn,w1[fa]);
  76. if(w2[fa])add(w2[fa],ne[tn]);
  77. add(s1,ne[tn]);
  78. add(tn,s2);
  79. }
  80. //puts("ww");
  81. w1[x]=s1;w2[x]=s2;
  82. if(t[x][0])add1[t[x][0]]|=add1[x],dfs(t[x][0],x);//传递子树标记
  83. if(t[x][1])add1[t[x][1]]|=add1[x],dfs(t[x][1],x);
  84. if(add2[x]&&add2[t[x][0]])mark=1;
  85. if(add2[x]&&add2[t[x][1]])mark=1;
  86. add2[x]|=add2[t[x][0]];//传递链上标记.
  87. add2[x]|=add2[t[x][1]];
  88. }
  89. int main()
  90. {
  91. freopen("code.in","r",stdin);
  92. freopen("code.out","w",stdout);
  93. ios::sync_with_stdio(false);
  94. cin>>n;//cout<<1<<endl;
  95. rep(1,n,i)cin>>a[i];
  96. rep(1,n,i)
  97. {
  98. ne[i]=i+n;ne[i+n]=i;
  99. for(ui j=0;j<a[i].size();++j)if(a[i][j]=='?'){flag[i]=j+1;break;}
  100. if(flag[i])
  101. {
  102. a[i][flag[i]-1]='0';
  103. insert(i,1);
  104. a[i][flag[i]-1]='1';
  105. insert(i+n,1);
  106. }
  107. else insert(i,0);
  108. }
  109. sum=2*n;dfs(1,0);
  110. if(mark){puts("NO");return 0;}
  111. rep(1,2*n,i)if(add1[pos[i]]||add2[pos[i]])if(pos[i])add(i,ne[i]);
  112. rep(1,2*n,i)if(!dfn[i])dfs(i);
  113. rep(1,n,i)if(c[i]==c[i+n]){puts("NO");return 0;}
  114. puts("YES");
  115. return 0;
  116. }

4.15 省选模拟赛 编码 trie树 前缀和优化建图 2-sat的更多相关文章

  1. 5.15 省选模拟赛 容斥 生成函数 dp

    LINK:5.15 T2 个人感觉生成函数更无脑 容斥也好推的样子. 容易想到每次放数和数字的集合无关 所以得到一个dp f[i][j]表示前i个数字 逆序对为j的方案数. 容易得到转移 使用前缀和优 ...

  2. 6.15 省选模拟赛 老魔杖 博弈论 SG函数

    这道题确实没有一个很好的解决办法 唯一的正解可能就是打表找规律 或者 直接猜结论了吧. 尽管如此 在此也给最终结论一个完整的证明. 对于70分 容易发现状态数量不大 可以进行暴力dp求SG函数. 原本 ...

  3. 5.15 省选模拟赛 T1 点分治 FFT

    LINK:5.15 T1 对于60分的暴力 都很水 就不一一赘述了. 由于是询问所有点的这种信息 确实不太会. 想了一下 如果只是询问子树内的话 dsu on tree还是可以做的. 可以自己思考一下 ...

  4. 5.4 省选模拟赛 修改 线段树优化dp 线段树上二分

    LINK:修改 题面就不放了 大致说一下做法.不愧是dls出的题 以前没见过这种类型的 不过还是自己dp的时候写丑了. 从这道题中得到一个结论 dp方程要写的优美一点 不过写的过丑 优化都优化不了. ...

  5. 4.9 省选模拟赛 圆圈游戏 树形dp set优化建图

    由于圆不存在相交的关系 所以包容关系形成了树的形态 其实是一个森林 不过加一个0点 就变成了树. 考虑对于每个圆都求出最近的包容它的点 即他的父亲.然后树形dp即可.暴力建图n^2. const in ...

  6. 【洛谷比赛】[LnOI2019]长脖子鹿省选模拟赛 T1 题解

    今天是[LnOI2019]长脖子鹿省选模拟赛的时间,小编表示考的不怎么样,改了半天也只会改第一题,那也先呈上题解吧. T1:P5248 [LnOI2019SP]快速多项式变换(FPT) 一看这题就很手 ...

  7. 【2019.7.26 NOIP模拟赛 T3】化学反应(reaction)(线段树优化建图+Tarjan缩点+拓扑排序)

    题意转化 考虑我们对于每一对激活关系建一条有向边,则对于每一个点,其答案就是其所能到达的点数. 于是,这个问题就被我们搬到了图上,成了一个图论题. 优化建图 考虑我们每次需要将一个区间向一个区间连边. ...

  8. 内存空间有限情况下的词频统计 Trie树 前缀树

    数据结构与算法专题--第十二题 Trie树 https://mp.weixin.qq.com/s/nndr2AcECuUatXrxd3MgCg

  9. 4.24 省选模拟赛 欧珀瑞特 主席树 可持久化trie树

    很容易的一道题目.大概.不过我空间计算失误MLE了 我草草的计算了一下没想到GG了. 关键的是 我学了一个dalao的空间回收的方法 但是弄巧成拙了. 题目没有明确指出 在任意时刻数组长度为有限制什么 ...

随机推荐

  1. mysql高可用架构MHA搭建(centos7+mysql5.7.28)

    无论是传统行业,还是互联网行业,数据可用性都是至关重要的,虽然现在已经步入大数据时代,nosql比较流行,但是作为数据持久化及事务性的关系型数据库依然是项目首选,比如mysql. 现在几乎所有的公司项 ...

  2. 洛谷P5774,可爱的动态规划。

    如此可爱的动态规划见过么? 相信各位都非常喜欢动态规划,那我就写一道可爱的动态规划的题解吧. 题目:https://www.luogu.com.cn/problem/P5774 题意: 题意“挺明白” ...

  3. 关于C++命名空间namespace的理解与使用介绍

    0X00 前言 所谓namespace,是指标识符的各种可见范围.C++标准程序库中的所有标识符都被定义于一个名为std的namespace中. 0x01 与C语言区别 <iostream> ...

  4. mui点击蒙版点击蒙版让其不自动关闭

    var mask = mui.createMask(callback);//callback为用户点击蒙版时自动执行的回调: mask.show();//显示遮罩 mask.close();//关闭遮 ...

  5. Scala 基础(十三):Scala 模式匹配(一)

    1 match 应用案例 Scala的模式匹配 案例代码完整: package com.atguigu.base object MatchDemo { def main(args: Array[Str ...

  6. P1536 村村通(洛谷)并查集

    隔壁的dgdger带我看了看老师的LCA教程,我因为学习数学太累了(就是懒),去水了一下,感觉很简单的样子,于是我也来写(水)个博客吧. 题目描述 某市调查城镇交通状况,得到现有城镇道路统计表.表中列 ...

  7. JavaScript动画实例:粒子文本

    1.粒子文本的实现原理 粒子文本的实现原理是:使用两张 canvas,一张是用户看不到的canvas1,用来绘制文本:另一张是用户看到的canvas2,用来根据canvas1中绘制的文本数据来生成粒子 ...

  8. Oracle DataGuard主备切换(switchover)

    Oracle DataGuard主备切换可以使用传统的手动命令切换,也可以使用dgmgr切换,本文记录手动切换. (一)将主库切换为物理备库 STEP1:查看主库状态 SQL> SELECT O ...

  9. v-bind v-on 缩写

    Vue.js 为两个最为常用的指令提供了特别的缩写:

  10. super,this关键字用法 Java

    super 用法 1.调用父类变量2.调用父类方法3.子类构造方法第一句 this 用法 super关键字用来访问父类内容, this 关键字用来访问本类中的内容, 有三种用法 1.在本类的成员方法中 ...