题解

我一直也不会网络流……orz

我们分析下这道题,显然和行列没啥关系,就是想给你n + m个串

那么我们对于非回文单词之外的单词,找到两两匹配的反转单词(即使另一个反转单词不会出现也要建出来)

具体就是我们建一个hash表,遇见一个单词读进来,把这个单词反转之后再存进哈希表里

然后我们把一对反转单词挑出来,按照字典序,字典序小的往字典序大的连一条流量为2的边

那么现在我们考虑一下加入阅读方式都已经被全部确定,那么网络流的建图方式就应该是

如果顺着给定的顺序是字典序较小的,那么就向给定循序读的单词连一条正无穷的边

如果顺着给定顺序是字典序较大的,那么给定顺序读出的单词就向这一行或一列连一条正无穷的边



跑最大流就是答案

现在我们有了未知顺序的边,那么我们就要求了某些单词(这里正反单词算一种)必须全是以字典序较小的方式读,或者全是以字典序较大的方式读

这个限制可以用最大流等于最小割,可以想一下

如果我们需要反转部分在某些串里字典序较小的单词,从而使整个0串全是字典序较大的单词,那么这些串所连的单词所在的边就会满流

同理,如果反转字典序较大的单词,靠近汇点的一边单词会满流

因为最大流等于最小割,所以总会选择较小的一边流满

所以我们的连边方式就是0串所有单词的字典序较大的一边向0串连正无穷边,0串向所有单词字典序较小的一边连正无穷的边

跑一遍最大流加上回文单词个数就是答案了

我的代码怎么又将近写了8K= =

代码

  1. #include <bits/stdc++.h>
  2. #define enter putchar('\n')
  3. #define space putchar(' ')
  4. #define pii pair<int,int>
  5. #define fi first
  6. #define se second
  7. #define mp make_pair
  8. #define MAXN 1000005
  9. #define mo 999999137
  10. #define pb push_back
  11. //#define ivorysi
  12. using namespace std;
  13. typedef long long int64;
  14. typedef double db;
  15. template<class T>
  16. void read(T &res) {
  17. res = 0;T f = 1;char c = getchar();
  18. while(c < '0' || c > '9') {
  19. if(c == '-') f = -1;
  20. c = getchar();
  21. }
  22. while(c >= '0' && c <= '9') {
  23. res = res * 10 + c - '0';
  24. c = getchar();
  25. }
  26. res *= f;
  27. }
  28. template<class T>
  29. void out(T x) {
  30. if(x < 0) {x = -x;putchar('-');}
  31. if(x >= 10) out(x / 10);
  32. putchar('0' + x % 10);
  33. }
  34. int N,M;
  35. char s[105][105];
  36. int H[105],L[105];
  37. int e[105];
  38. struct Word{
  39. char s[75];
  40. int hsh;
  41. friend bool operator < (const Word &a,const Word &b) {
  42. return a.hsh < b.hsh;
  43. }
  44. friend bool operator == (const Word &a,const Word &b) {
  45. return a.hsh == b.hsh;
  46. }
  47. }C[10005];
  48. int op[10005],revcnt;
  49. bool rev[10005],isSmall[10005];
  50. struct node {
  51. int to,next,cap;
  52. }E[100005];
  53. int sumE,head[10005],cnt,S,T;
  54. int last[10005],dis[10005],gap[10005];
  55. map<int,int> hash_list;
  56. vector<int> W;
  57. void add(int u,int v,int c) {
  58. E[++sumE].to = v;
  59. E[sumE].next = head[u];
  60. E[sumE].cap = c;
  61. head[u] = sumE;
  62. }
  63. void addtwo(int u,int v,int c) {
  64. add(u,v,c);add(v,u,0);
  65. }
  66. int calc(char *s,int len) {
  67. int res = 0;
  68. for(int i = 1 ; i <= len ; ++i) {
  69. res = (res + 1LL * e[i - 1] * (s[i] - 'A' + 1) % mo) % mo;
  70. }
  71. return res;
  72. }
  73. void Insert(int id,char *t,int len) {
  74. t[len + 1] = '\0';
  75. memcpy(C[id].s,t,sizeof(char) * (len + 2));
  76. C[id].hsh = calc(t,len);
  77. }
  78. bool cmp(char *s,char *t,int len) {
  79. for(int i = 1 ; i <= len ; ++i) {
  80. if(s[i] != t[i]) return s[i] < t[i];
  81. }
  82. return 0;
  83. }
  84. int sap(int u,int aug) {
  85. if(u == T) return aug;
  86. int flow = 0;
  87. for(int i = last[u] ; i ; i = E[i].next) {
  88. int v = E[i].to;
  89. if(dis[v] + 1 == dis[u]) {
  90. int t = sap(v,min(aug - flow,E[i].cap));
  91. flow += t;
  92. E[i].cap -= t;
  93. E[i ^ 1].cap += t;
  94. if(aug == flow) return flow;
  95. if(dis[S] >= T) return flow;
  96. }
  97. }
  98. --gap[dis[u]];if(!gap[dis[u]]) dis[S] = T;++gap[++dis[u]];last[u] = head[u];
  99. return flow;
  100. }
  101. void Init() {
  102. read(N);read(M);
  103. for(int i = 1 ; i <= N ; ++i) read(H[i]);
  104. for(int i = 1 ; i <= M ; ++i) read(L[i]);
  105. for(int i = 1 ; i <= N ; ++i) scanf("%s",s[i] + 1);
  106. memset(head,0,sizeof(head));sumE = 1;
  107. hash_list.clear();
  108. memset(rev,0,sizeof(rev));revcnt = 0;
  109. memset(isSmall,0,sizeof(isSmall));
  110. memset(dis,0,sizeof(dis));
  111. memset(gap,0,sizeof(gap));
  112. }
  113. void Solve() {
  114. Init();
  115. char tmp[75];
  116. memset(tmp,0,sizeof(tmp));
  117. int tot = 0;
  118. cnt = 0;
  119. for(int i = 1 ; i <= N ; ++i) {
  120. tot = 0;
  121. for(int j = 1 ; j <= M ; ++j) {
  122. if(s[i][j] == '_') {
  123. if(tot) {
  124. Insert(++cnt,tmp,tot);
  125. reverse(tmp + 1,tmp + tot + 1);
  126. Insert(++cnt,tmp,tot);
  127. }
  128. tot = 0;
  129. }
  130. else tmp[++tot] = s[i][j];
  131. }
  132. if(tot) {
  133. Insert(++cnt,tmp,tot);
  134. reverse(tmp + 1,tmp + tot + 1);
  135. Insert(++cnt,tmp,tot);
  136. }
  137. }
  138. for(int j = 1 ; j <= M ; ++j) {
  139. tot = 0;
  140. for(int i = 1 ; i <= N ; ++i) {
  141. if(s[i][j] == '_') {
  142. if(tot) {
  143. Insert(++cnt,tmp,tot);
  144. reverse(tmp + 1,tmp + tot + 1);
  145. Insert(++cnt,tmp,tot);
  146. }
  147. tot = 0;
  148. }
  149. else tmp[++tot] = s[i][j];
  150. }
  151. if(tot) {
  152. Insert(++cnt,tmp,tot);
  153. reverse(tmp + 1,tmp + tot + 1);
  154. Insert(++cnt,tmp,tot);
  155. }
  156. }
  157. sort(C + 1,C + cnt + 1);
  158. cnt = unique(C + 1,C + cnt + 1) - C - 1;
  159. for(int i = 1 ; i <= cnt ; ++i) {
  160. hash_list[C[i].hsh] = i;
  161. }
  162. for(int i = 1 ; i <= cnt ; ++i) {
  163. memcpy(tmp,C[i].s,sizeof(tmp));
  164. int l = strlen(tmp + 1);
  165. reverse(tmp + 1,tmp + l + 1);
  166. if(calc(tmp,l) == C[i].hsh) {op[i] = i;rev[i] = 1;++revcnt;}
  167. else if(cmp(C[i].s,tmp,l)) {
  168. op[i] = hash_list[calc(tmp,l)];
  169. op[op[i]] = i;
  170. isSmall[i] = 1;isSmall[op[i]] = 0;
  171. addtwo(i,op[i],2);
  172. }
  173. }
  174. S = cnt + N + M + 1;T = S + 1;
  175. for(int i = 1 ; i <= N ; ++i) {
  176. W.clear();
  177. tot = 0;
  178. for(int j = 1 ; j <= M ; ++j) {
  179. if(s[i][j] == '_') {
  180. if(tot) {
  181. int t = hash_list[calc(tmp,tot)];
  182. if(!rev[t]) W.pb(t);
  183. }
  184. tot = 0;
  185. }
  186. else tmp[++tot] = s[i][j];
  187. }
  188. if(tot) {int t = hash_list[calc(tmp,tot)];if(!rev[t]) W.pb(t);}
  189. if(!W.size()) continue;
  190. sort(W.begin(),W.end());W.erase(unique(W.begin(),W.end()),W.end());
  191. int siz = W.size();
  192. if((H[i] == 1 && isSmall[W[0]]) || (H[i] == -1 && !isSmall[W[0]])) {
  193. addtwo(S,cnt + i,0x7fffffff);
  194. for(int j = 0 ; j < siz ; ++j) {
  195. if(isSmall[W[j]]) addtwo(cnt + i,W[j],0x7fffffff);
  196. else addtwo(cnt + i,op[W[j]],0x7fffffff);
  197. }
  198. }
  199. else if((H[i] == 1 && !isSmall[W[0]]) || (H[i] == -1 && isSmall[W[0]])) {
  200. addtwo(cnt + i,T,0x7fffffff);
  201. for(int j = 0 ; j < siz ; ++j) {
  202. if(!isSmall[W[j]]) addtwo(W[j],cnt + i,0x7fffffff);
  203. else addtwo(op[W[j]],cnt + i,0x7fffffff);
  204. }
  205. }
  206. else if(H[i] == 0) {
  207. if(!isSmall[W[0]]) {
  208. for(int j = 0 ; j < siz ; ++j) {
  209. W[j] = op[W[j]];
  210. }
  211. }
  212. for(int j = 0 ; j < siz ; ++j) {
  213. addtwo(cnt + i,W[j],0x7fffffff);
  214. addtwo(op[W[j]],cnt + i,0x7fffffff);
  215. }
  216. }
  217. }
  218. for(int j = 1 ; j <= M ; ++j) {
  219. W.clear();
  220. tot = 0;
  221. for(int i = 1 ; i <= N ; ++i) {
  222. if(s[i][j] == '_') {
  223. if(tot) {
  224. int t = hash_list[calc(tmp,tot)];
  225. if(!rev[t]) W.pb(t);
  226. }
  227. tot = 0;
  228. }
  229. else tmp[++tot] = s[i][j];
  230. }
  231. if(tot) {int t = hash_list[calc(tmp,tot)];if(!rev[t]) W.pb(t);}
  232. if(!W.size()) continue;
  233. sort(W.begin(),W.end());W.erase(unique(W.begin(),W.end()),W.end());
  234. int siz = W.size();
  235. if((L[j] == 1 && isSmall[W[0]]) || (L[j] == -1 && !isSmall[W[0]])) {
  236. addtwo(S,cnt + N + j,0x7fffffff);
  237. for(int i = 0 ; i < siz ; ++i) {
  238. if(isSmall[W[i]]) addtwo(cnt + N + j,W[i],0x7fffffff);
  239. else addtwo(cnt + N + j,op[W[i]],0x7fffffff);
  240. }
  241. }
  242. else if((L[j] == 1 && !isSmall[W[0]]) || (L[j] == -1 && isSmall[W[0]])) {
  243. addtwo(cnt + N + j,T,0x7fffffff);
  244. for(int i = 0 ; i < siz ; ++i) {
  245. if(!isSmall[W[i]]) addtwo(W[i],cnt + N + j,0x7fffffff);
  246. else addtwo(op[W[i]],cnt + N + j,0x7fffffff);
  247. }
  248. }
  249. else if(L[j] == 0) {
  250. if(!isSmall[W[0]]) {
  251. for(int i = 0 ; i < siz ; ++i) {
  252. W[i] = op[W[i]];
  253. }
  254. }
  255. for(int i = 0 ; i < siz ; ++i) {
  256. addtwo(cnt + N + j,W[i],0x7fffffff);
  257. addtwo(op[W[i]],cnt + N + j,0x7fffffff);
  258. }
  259. }
  260. }
  261. for(int i = 1 ; i <= T ; ++i) last[i] = head[i];
  262. int ans = revcnt;
  263. while(dis[S] < T) ans += sap(S,0x7fffffff);
  264. out(ans);enter;
  265. }
  266. int main() {
  267. #ifdef ivorysi
  268. freopen("f1.in","r",stdin);
  269. #endif
  270. e[0] = 1;
  271. for(int i = 1 ; i <= 100 ; ++i) e[i] = e[i - 1] * 47 % mo;
  272. int T;
  273. read(T);
  274. while(T--) {
  275. Solve();
  276. }
  277. return 0;
  278. }

【LOJ】#2066. 「SDOI2016」墙上的句子的更多相关文章

  1. [LOJ 2070] 「SDOI2016」平凡的骰子

    [LOJ 2070] 「SDOI2016」平凡的骰子 [题目链接] 链接 [题解] 原题求的是球面面积 可以理解为首先求多面体重心,然后算球面多边形的面积 求重心需要将多面体进行四面体剖分,从而计算出 ...

  2. LOJ#2070. 「SDOI2016」平凡的骰子(计算几何)

    题面 传送门 做一道题学一堆东西不管什么时候都是美好的体验呢-- 前置芝士 混合积 对于三个三维向量\(a,b,c\),定义它们的混合积为\((a\times b)\cdot c\),其中$\time ...

  3. Loj #2192. 「SHOI2014」概率充电器

    Loj #2192. 「SHOI2014」概率充电器 题目描述 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: 「采用全新纳米级加工技术,实现元件与导线能否通电完 ...

  4. Loj #3096. 「SNOI2019」数论

    Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...

  5. Loj #3093. 「BJOI2019」光线

    Loj #3093. 「BJOI2019」光线 题目描述 当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收. 设对于任意 \(x\),有 \(x\t ...

  6. Loj #3089. 「BJOI2019」奥术神杖

    Loj #3089. 「BJOI2019」奥术神杖 题目描述 Bezorath 大陆抵抗地灾军团入侵的战争进入了僵持的阶段,世世代代生活在 Bezorath 这片大陆的精灵们开始寻找远古时代诸神遗留的 ...

  7. Loj #2542. 「PKUWC2018」随机游走

    Loj #2542. 「PKUWC2018」随机游走 题目描述 给定一棵 \(n\) 个结点的树,你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去. 有 \(Q\) 次询问,每次 ...

  8. Loj #3059. 「HNOI2019」序列

    Loj #3059. 「HNOI2019」序列 给定一个长度为 \(n\) 的序列 \(A_1, \ldots , A_n\),以及 \(m\) 个操作,每个操作将一个 \(A_i\) 修改为 \(k ...

  9. Loj #3056. 「HNOI2019」多边形

    Loj #3056. 「HNOI2019」多边形 小 R 与小 W 在玩游戏. 他们有一个边数为 \(n\) 的凸多边形,其顶点沿逆时针方向标号依次为 \(1,2,3, \ldots , n\).最开 ...

随机推荐

  1. P1792 [国家集训队]种树

    P1792 [国家集训队]种树 题目描述 A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树. 园林部门得到指令后,初步规划出n个种树的位置,顺时针编号1到n.并且每 ...

  2. caffe 用faster rcnn 训练自己的数据 遇到的问题

    1 . 怎么处理那些pyx和.c .h文件 在lib下有一些文件为.pyx文件,遇到不能import可以cython 那个文件,然后把lib文件夹重新make一下. 遇到.c 和 .h一样的操作. 2 ...

  3. 视音频数据处理入门:FLV封装格式解析

    ===================================================== 视音频数据处理入门系列文章: 视音频数据处理入门:RGB.YUV像素数据处理 视音频数据处理 ...

  4. Document对象中的一些重要的属性和方法(笔记)

    Document对象:每一个web浏览器窗口.标签页和框架由一个window对象所表示.每个window对象都有一个document属性引用的是Document对象,它是一个巨大的API中的核心对象, ...

  5. “榕树下·那年”移动app ( hybrid ) 开发总结

        榕树下网站本身的技术人员并不多,所以app开发的任务就到了母公司盛大文学这边.       盛大文学无线业务中心负责这次具体开发任务.       一如既往的,开发的情况是:时间紧,任务重,人 ...

  6. 关于getsockname()/getpeername()函数第一次被调用得到0.0.0.0结果的说明

    最近阅读UNIX网络编程第四章时,书本末尾介绍了两个函数getsockname()和getpeername(),可以用于获取服务器端和客户端的IP地址与端口,原本很简单的两个函数,过一眼即明白函数的用 ...

  7. 利用SSLStrip截获https协议--抓取邮箱等密码

    1.SSL解析 SSL 是 Secure Socket Layer 的简称, 中文意思是安全套接字层,由 NetScape公司所开发,用以保障在 Internet 上数据传输的安全,确保数据在网络的传 ...

  8. 【Python项目】简单爬虫批量获取资源网站的下载链接

    简单爬虫批量获取资源网站的下载链接 项目链接:https://github.com/RealIvyWong/GotDownloadURL 1 由来 自己在收集剧集资源的时候,这些网站的下载链接还要手动 ...

  9. 一个不错的linux学习资料下载的网址

    本文比较完整的讲述GNU make工具,涵盖GNU make的用法.语法.同时重点讨论如何为一个工程编写Makefile.作为一个Linux程序员,make工具的使用以及编写Makefile是必需的. ...

  10. Linux压缩打包方法连载之三:bzip2, bzcat 命令

    Linux压缩打包方法有多种,本文集中讲解了bzip2, bzcat 命令的使用.案例说明,例如# 与 gzip 同样的,都是在计算压缩比的参数,-9 最佳,-1 最快. AD: 我们遇见Linux压 ...