题解

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

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

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

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

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

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

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

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



跑最大流就是答案

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

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

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

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

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

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

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

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

代码

#include <bits/stdc++.h>
#define enter putchar('\n')
#define space putchar(' ')
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
#define MAXN 1000005
#define mo 999999137
#define pb push_back
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;T f = 1;char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) out(x / 10);
putchar('0' + x % 10);
}
int N,M;
char s[105][105];
int H[105],L[105];
int e[105];
struct Word{
char s[75];
int hsh;
friend bool operator < (const Word &a,const Word &b) {
return a.hsh < b.hsh;
}
friend bool operator == (const Word &a,const Word &b) {
return a.hsh == b.hsh;
}
}C[10005];
int op[10005],revcnt;
bool rev[10005],isSmall[10005];
struct node {
int to,next,cap;
}E[100005];
int sumE,head[10005],cnt,S,T;
int last[10005],dis[10005],gap[10005];
map<int,int> hash_list;
vector<int> W;
void add(int u,int v,int c) {
E[++sumE].to = v;
E[sumE].next = head[u];
E[sumE].cap = c;
head[u] = sumE;
}
void addtwo(int u,int v,int c) {
add(u,v,c);add(v,u,0);
}
int calc(char *s,int len) {
int res = 0;
for(int i = 1 ; i <= len ; ++i) {
res = (res + 1LL * e[i - 1] * (s[i] - 'A' + 1) % mo) % mo;
}
return res;
}
void Insert(int id,char *t,int len) {
t[len + 1] = '\0';
memcpy(C[id].s,t,sizeof(char) * (len + 2));
C[id].hsh = calc(t,len);
} bool cmp(char *s,char *t,int len) {
for(int i = 1 ; i <= len ; ++i) {
if(s[i] != t[i]) return s[i] < t[i];
}
return 0;
}
int sap(int u,int aug) {
if(u == T) return aug;
int flow = 0;
for(int i = last[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(dis[v] + 1 == dis[u]) {
int t = sap(v,min(aug - flow,E[i].cap));
flow += t;
E[i].cap -= t;
E[i ^ 1].cap += t;
if(aug == flow) return flow;
if(dis[S] >= T) return flow;
}
}
--gap[dis[u]];if(!gap[dis[u]]) dis[S] = T;++gap[++dis[u]];last[u] = head[u];
return flow;
}
void Init() {
read(N);read(M);
for(int i = 1 ; i <= N ; ++i) read(H[i]);
for(int i = 1 ; i <= M ; ++i) read(L[i]);
for(int i = 1 ; i <= N ; ++i) scanf("%s",s[i] + 1);
memset(head,0,sizeof(head));sumE = 1;
hash_list.clear();
memset(rev,0,sizeof(rev));revcnt = 0;
memset(isSmall,0,sizeof(isSmall));
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap)); }
void Solve() {
Init();
char tmp[75];
memset(tmp,0,sizeof(tmp));
int tot = 0;
cnt = 0;
for(int i = 1 ; i <= N ; ++i) {
tot = 0;
for(int j = 1 ; j <= M ; ++j) {
if(s[i][j] == '_') {
if(tot) {
Insert(++cnt,tmp,tot);
reverse(tmp + 1,tmp + tot + 1);
Insert(++cnt,tmp,tot);
}
tot = 0;
}
else tmp[++tot] = s[i][j];
}
if(tot) {
Insert(++cnt,tmp,tot);
reverse(tmp + 1,tmp + tot + 1);
Insert(++cnt,tmp,tot);
}
}
for(int j = 1 ; j <= M ; ++j) {
tot = 0;
for(int i = 1 ; i <= N ; ++i) {
if(s[i][j] == '_') {
if(tot) {
Insert(++cnt,tmp,tot);
reverse(tmp + 1,tmp + tot + 1);
Insert(++cnt,tmp,tot);
}
tot = 0;
}
else tmp[++tot] = s[i][j];
}
if(tot) {
Insert(++cnt,tmp,tot);
reverse(tmp + 1,tmp + tot + 1);
Insert(++cnt,tmp,tot);
}
}
sort(C + 1,C + cnt + 1);
cnt = unique(C + 1,C + cnt + 1) - C - 1;
for(int i = 1 ; i <= cnt ; ++i) {
hash_list[C[i].hsh] = i;
}
for(int i = 1 ; i <= cnt ; ++i) {
memcpy(tmp,C[i].s,sizeof(tmp));
int l = strlen(tmp + 1);
reverse(tmp + 1,tmp + l + 1);
if(calc(tmp,l) == C[i].hsh) {op[i] = i;rev[i] = 1;++revcnt;}
else if(cmp(C[i].s,tmp,l)) {
op[i] = hash_list[calc(tmp,l)];
op[op[i]] = i;
isSmall[i] = 1;isSmall[op[i]] = 0;
addtwo(i,op[i],2);
}
}
S = cnt + N + M + 1;T = S + 1;
for(int i = 1 ; i <= N ; ++i) {
W.clear();
tot = 0;
for(int j = 1 ; j <= M ; ++j) {
if(s[i][j] == '_') {
if(tot) {
int t = hash_list[calc(tmp,tot)];
if(!rev[t]) W.pb(t);
}
tot = 0;
}
else tmp[++tot] = s[i][j];
}
if(tot) {int t = hash_list[calc(tmp,tot)];if(!rev[t]) W.pb(t);}
if(!W.size()) continue;
sort(W.begin(),W.end());W.erase(unique(W.begin(),W.end()),W.end());
int siz = W.size();
if((H[i] == 1 && isSmall[W[0]]) || (H[i] == -1 && !isSmall[W[0]])) {
addtwo(S,cnt + i,0x7fffffff);
for(int j = 0 ; j < siz ; ++j) {
if(isSmall[W[j]]) addtwo(cnt + i,W[j],0x7fffffff);
else addtwo(cnt + i,op[W[j]],0x7fffffff);
}
}
else if((H[i] == 1 && !isSmall[W[0]]) || (H[i] == -1 && isSmall[W[0]])) {
addtwo(cnt + i,T,0x7fffffff);
for(int j = 0 ; j < siz ; ++j) {
if(!isSmall[W[j]]) addtwo(W[j],cnt + i,0x7fffffff);
else addtwo(op[W[j]],cnt + i,0x7fffffff);
}
}
else if(H[i] == 0) {
if(!isSmall[W[0]]) {
for(int j = 0 ; j < siz ; ++j) {
W[j] = op[W[j]];
}
}
for(int j = 0 ; j < siz ; ++j) {
addtwo(cnt + i,W[j],0x7fffffff);
addtwo(op[W[j]],cnt + i,0x7fffffff);
}
}
}
for(int j = 1 ; j <= M ; ++j) {
W.clear();
tot = 0;
for(int i = 1 ; i <= N ; ++i) {
if(s[i][j] == '_') {
if(tot) {
int t = hash_list[calc(tmp,tot)];
if(!rev[t]) W.pb(t);
}
tot = 0;
}
else tmp[++tot] = s[i][j];
}
if(tot) {int t = hash_list[calc(tmp,tot)];if(!rev[t]) W.pb(t);}
if(!W.size()) continue;
sort(W.begin(),W.end());W.erase(unique(W.begin(),W.end()),W.end());
int siz = W.size();
if((L[j] == 1 && isSmall[W[0]]) || (L[j] == -1 && !isSmall[W[0]])) {
addtwo(S,cnt + N + j,0x7fffffff);
for(int i = 0 ; i < siz ; ++i) {
if(isSmall[W[i]]) addtwo(cnt + N + j,W[i],0x7fffffff);
else addtwo(cnt + N + j,op[W[i]],0x7fffffff);
}
}
else if((L[j] == 1 && !isSmall[W[0]]) || (L[j] == -1 && isSmall[W[0]])) {
addtwo(cnt + N + j,T,0x7fffffff);
for(int i = 0 ; i < siz ; ++i) {
if(!isSmall[W[i]]) addtwo(W[i],cnt + N + j,0x7fffffff);
else addtwo(op[W[i]],cnt + N + j,0x7fffffff);
}
}
else if(L[j] == 0) {
if(!isSmall[W[0]]) {
for(int i = 0 ; i < siz ; ++i) {
W[i] = op[W[i]];
}
}
for(int i = 0 ; i < siz ; ++i) {
addtwo(cnt + N + j,W[i],0x7fffffff);
addtwo(op[W[i]],cnt + N + j,0x7fffffff);
}
}
}
for(int i = 1 ; i <= T ; ++i) last[i] = head[i];
int ans = revcnt;
while(dis[S] < T) ans += sap(S,0x7fffffff);
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
e[0] = 1;
for(int i = 1 ; i <= 100 ; ++i) e[i] = e[i - 1] * 47 % mo;
int T;
read(T);
while(T--) {
Solve();
}
return 0;
}

【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. python中高阶函数与装饰器

    高阶函数的定义:传入参数有函数名或者返回值有内置函数名的函数. 最简单的高阶函数: def add(x, y, f):    return f(x) + f(y) add(-5, 6, abs) 常用 ...

  2. [整理]C语言函数说明和定义

    函数的一般形式是:type-specifier function_name(parameter list) parameter declarations{   body of the function ...

  3. 20145202马超 2016-2017-2 《Java程序设计》第6周学习总结

    20145202马超 2016-2017-2 <Java程序设计>第6周学习总结 教材学习内容总结 进程:是一个正在执行中的程序,每一个进程都有一个执行程序,该顺序是一个执行路径,或者说是 ...

  4. zabbix lld使用trapper方式(zabbix_sender)

    自动发现脚本文件输出格式: { "data": [ { "{#BIND_PERF}": "BIND INCOMING QUERY" }, { ...

  5. 【leetcode 简单】 第九十七题 快乐数

    写一个程序,输出从 1 到 n 数字的字符串表示. 1. 如果 n 是3的倍数,输出“Fizz”: 2. 如果 n 是5的倍数,输出“Buzz”: 3.如果 n 同时是3和5的倍数,输出 “FizzB ...

  6. 解决 Electron 包下载太慢问题

    项目下新建 .npmrc 文件,加入如下配置: electron_mirror=https://npm.taobao.org/mirrors/electron/ 即使用淘宝的源,重新 npm inst ...

  7. 2016.07.13-vector<vector<int>>应用2——Two Sum扩展

    收获: vector<vector<int> >res,不能直接用res[j].push_back(number),因为res[j]是空的,没有初始化 可以先定义 vector ...

  8. 64位linux安装32位校园网客户端

    下面的是ubuntu下和arch下的安装方法,ubuntu的转自网络, ubuntu: 下载客户端并解压 安装开发包 1 sudo -i 2 dpkg --add-architecture i386 ...

  9. Django 内置模板标签和过滤器

    一.内置模板标签 语法:{%  %} autoescape : 是否转义,on或off作为参数,并确定自动转义是否在块内有效.该块以endautoescape结束 {% autoescape on % ...

  10. Python基础:内置类型(未完待续)

    本文根据Python 3.6.5的官文Built-in Types而写. 目录 1.真值测试 2.布尔操作 -- and, or, not 3.比较 4.数字型 -- int, float, comp ...