标签:技术分享 trie树 搜索 tac 初始 add bfs 理解 size
好久没有模拟了,然后一模拟就gg……
T1 高维宇宙
因为模拟标题上写的noip,所以当时我就压根没往二分图匹配想,而是生成了了一个像邻接矩阵的表,t[i][j]表示 a[i] + a[j],然后在倒三角矩阵里爆搜……虽然加上了如果加上当前最大值仍小于ans就返回的剪枝,但还是稳稳地30分……果然搜索的复杂度不可预料啊。
正解嘛,因为题中说到了匹配,那自然是二分图匹配或网络流了。因此重在建图:首先必须满足是二分图,那么想一想就得出,一定是一个奇数和一个偶数相加才可能得到一个质数。因此二分图就建成了:一半是偶数,一般是奇数,然后把偶数都连一条流量为1通向源点的边,奇数连一条通向汇点的边,然后如果两数之和为质数,就连边。
跑网络流或匈牙利就行了~~
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<vector> 9 #include<stack> 10 #include<queue> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(‘ ‘) 14 #define Mem(a) memset(a, 0, sizeof(a)) 15 typedef long long ll; 16 typedef double db; 17 const int INF = 0x3f3f3f3f; 18 const db eps = 1e-8; 19 const int max_num = 2e3 + 5; 20 const int maxn = 45; 21 inline ll read() 22 { 23 ll ans = 0; 24 char ch = getchar(), last = ‘ ‘; 25 while(!isdigit(ch)) {last = ch; ch = getchar();} 26 while(isdigit(ch)) {ans = ans * 10 + ch - ‘0‘; ch = getchar();} 27 if(last == ‘-‘) ans = -ans; 28 return ans; 29 } 30 inline void write(ll x) 31 { 32 if(x < 0) x = -x, putchar(‘-‘); 33 if(x >= 10) write(x / 10); 34 putchar(x % 10 + ‘0‘); 35 } 36 37 int n, t, a[maxn]; 38 bool prime[max_num] = {0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0}; 39 40 struct Edge 41 { 42 int from, to, cap, flow; 43 }; 44 vector<Edge> edges; 45 vector<int> G[maxn << 2]; 46 void addedge(int from, int to) 47 { 48 edges.push_back((Edge){from, to, 1, 0}); 49 edges.push_back((Edge){to, from, 0, 0}); 50 int sz = edges.size(); 51 G[from].push_back(sz - 2); 52 G[to].push_back(sz - 1); 53 } 54 55 int dis[maxn << 2]; 56 bool vis[maxn << 2]; 57 bool bfs() 58 { 59 Mem(vis); 60 queue<int> q; 61 q.push(0); vis[0] = 1; 62 dis[0] = 0; 63 while(!q.empty()) 64 { 65 int now = q.front(); q.pop(); 66 for(int i = 0; i < (int)G[now].size(); ++i) 67 { 68 Edge& e = edges[G[now][i]]; 69 if(!vis[e.to] && e.cap > e.flow) 70 { 71 vis[e.to] = 1; 72 dis[e.to] = dis[now] + 1; 73 q.push(e.to); 74 } 75 } 76 } 77 return vis[t]; 78 } 79 int cur[maxn << 2]; 80 int dfs(int now, int a) 81 { 82 if(now == t || !a) return a; 83 int flow = 0, f; 84 for(int& i = cur[now]; i < (int)G[now].size(); ++i) 85 { 86 Edge& e = edges[G[now][i]]; 87 if(dis[e.to] == dis[now] + 1 && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0) 88 { 89 e.flow += f; 90 edges[G[now][i] ^ 1].flow -= f; 91 flow += f; a -= f; 92 if(!a) break; 93 } 94 } 95 return flow; 96 } 97 98 int maxflow() 99 { 100 int flow = 0; 101 while(bfs()) 102 { 103 Mem(cur); 104 flow += dfs(0, INF); 105 } 106 return flow; 107 } 108 109 int main() 110 { 111 freopen("prime.in", "r", stdin); 112 freopen("prime.out", "w", stdout); 113 n = read(); t = n + n + 1; 114 for(int i = 1; i <= n; ++i) a[i] = read(); 115 for(int i = 1; i <= n; ++i) 116 { 117 if(!(a[i] & 1)) addedge(0, i); 118 else addedge(i + n, t); 119 if(!(a[i] & 1)) for(int j = 1; j <= n; ++j) 120 if(prime[a[i] + a[j]]) addedge(i, n + j); 121 } 122 write(maxflow()); enter; 123 return 0; 124 }
T2 旅行
这道题模拟的时候看错了……看成可以同时走很多边,像网络流那种。然而题中明确的说出是只能选一条路径,要不然“(若有多组解取字典序最小的一组 )”这句话干啥……
按我错误的理解,我就先正着bfs一遍,再反着bfs一遍,然后两次都标记的点就是在1到n路径上的点,然后对于这些点连的边的[L, R],用线段树维护即可。(虽然题意理解错了,但我觉得我这算法挺完美的)
正解我写的是一种比较诡异的dijkstra,interestingLSY大佬给我讲的。首先我们从小到大枚举L,然后把所有a[i].L <= L <= a[i].R的边都加入图中构成一个新的图,换句话说就是把可能使L成为答案的边加入图中。然后在这个图上跑dijkstra(或者更像是dp):令dis[i]表示到结点 i 满足条件的R的最大值,则当执行u到v的松弛操作时,dis[v] = min(dis[u], a[u->v].R)。那么最后的dis[n]就是当答案,用dis[n] - L尝试去更新最终的答案。
这时会有人问:因为我们加入的边只是满足a[i].L <= L <= a[i].R,所以实际上dis[n] - L可能不是最优的答案,可能是某一个的a[i].L。这不成问题,因为这种情况一定会在枚举更小的L的时候考虑到。
代码实现上其实不用反复建图,只用判断当前的边是否符合条件,如符合,就加入优先队列。
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<vector> 9 #include<stack> 10 #include<queue> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(‘ ‘) 14 #define Mem(a) memset(a, 0, sizeof(a)) 15 typedef long long ll; 16 typedef double db; 17 const int INF = 0x3f3f3f3f; 18 const db eps = 1e-8; 19 const int maxn = 1e3 + 5; 20 const int maxm = 3e3 + 5; 21 inline ll read() 22 { 23 ll ans = 0; 24 char ch = getchar(), last = ‘ ‘; 25 while(!isdigit(ch)) {last = ch; ch = getchar();} 26 while(isdigit(ch)) {ans = ans * 10 + ch - ‘0‘; ch = getchar();} 27 if(last == ‘-‘) ans = -ans; 28 return ans; 29 } 30 inline void write(ll x) 31 { 32 if(x < 0) x = -x, putchar(‘-‘); 33 if(x >= 10) write(x / 10); 34 putchar(x % 10 + ‘0‘); 35 } 36 37 int n, m, l[maxm]; 38 struct Node 39 { 40 int to, L, R; 41 }; 42 vector<Node> v[maxn]; 43 44 #define pr pair<int, int> 45 #define mp make_pair 46 int dis[maxn]; 47 bool in[maxn]; 48 int dijkstra(int l) 49 { 50 Mem(in); Mem(dis); 51 dis[1] = INF; //dis[1]要初始化为INF 52 priority_queue<pr> q; 53 q.push(mp(dis[1], 1)); 54 while(!q.empty()) 55 { 56 int now = q.top().second; q.pop(); 57 if(in[now]) continue; 58 in[now] = 1; 59 for(int i = 0; i < (int)v[now].size(); ++i) 60 { 61 if(v[now][i].L <= l && l <= v[now][i].R && dis[v[now][i].to] < min(dis[now], v[now][i].R)) //注意条件 62 { 63 dis[v[now][i].to] = min(dis[now], v[now][i].R); 64 q.push(mp(dis[v[now][i].to], v[now][i].to)); 65 } 66 } 67 } 68 return dis[n]; 69 } 70 71 int lft = 0, rgt = 0; 72 73 int main() 74 { 75 freopen("travel.in", "r", stdin); 76 freopen("travel.out", "w", stdout); 77 n = read(); m = read(); 78 for(int i = 1; i <= m; ++i) 79 { 80 int x = read(), y = read(), L = read(), R = read(); 81 l[i] = L; 82 v[x].push_back((Node){y, L, R}); v[y].push_back((Node){x, L, R}); 83 } 84 sort(l + 1, l + m + 1); 85 int _m = unique(l + 1, l + m + 1) - l - 1; 86 for(int i = 1; i <= _m; ++i) 87 { 88 int R = dijkstra(l[i]); 89 if(R - l[i] > rgt - lft) lft = l[i], rgt = R; 90 } 91 write(rgt - lft + 1); enter; 92 if(!lft && !rgt) return 0; 93 for(int i = lft; i <= rgt; ++i) write(i), space; enter; 94 return 0; 95 }
T3 词典
这道题第一反应是hash,然后发现是一个很稳的O(n2)做法只能得30分。然后就想到了trie树,但是实在没想出来如何去维护a数组,就打算30分跑路了,结果MLE,哎nb!没想到忘算空间复杂度了。不过这幸亏发生在平时的模拟上,给我这个教训,而不是noip现场上……
标程实际上是在trie树上每一个结点开了一个vector,记录第几个字符串经过该点,然后查询的时候到结点 i,就遍历nd[i](nd是vector),暴力更新答案。然而这么会TLE,不过只要再开一个vis数组,求过的点就不用再求了。复杂度最坏最坏好像是O(∑lens * n),n是遍历vector的复杂度。不过实际上远远没有达到这个地步,因为字母只有a, b, c,所以n个字符串中公用的结点会很多,查询到相同的结点的概率会很大,所以实际上遍历vector的复杂度远小于n。
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<vector> 9 #include<stack> 10 #include<queue> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(‘ ‘) 14 #define Mem(a) memset(a, 0, sizeof(a)) 15 typedef long long ll; 16 typedef double db; 17 const int INF = 0x3f3f3f3f; 18 const db eps = 1e-8; 19 const int maxn = 5e6 + 5; 20 inline ll read() 21 { 22 ll ans = 0; 23 char ch = getchar(), last = ‘ ‘; 24 while(!isdigit(ch)) {last = ch; ch = getchar();} 25 while(isdigit(ch)) {ans = ans * 10 + ch - ‘0‘; ch = getchar();} 26 if(last == ‘-‘) ans = -ans; 27 return ans; 28 } 29 inline void write(ll x) 30 { 31 if(x < 0) x = -x, putchar(‘-‘); 32 if(x >= 10) write(x / 10); 33 putchar(x % 10 + ‘0‘); 34 } 35 36 int n, m; 37 int ch[maxn][3], tot = 0; 38 vector<int> nd[maxn]; 39 int vis[maxn]; 40 void insert(int id, char* s) 41 { 42 int m = strlen(s), now = 0; 43 for(int i = 0; i < m; ++i) 44 { 45 int c = s[i] - ‘a‘; 46 if(!ch[now][c]) ch[now][c] = ++tot; 47 now = ch[now][c]; 48 nd[now].push_back(id); 49 } 50 } 51 int query(char *s) 52 { 53 int m = strlen(s), now = 0; 54 for(int i = 0; i < m; ++i) 55 { 56 int c = s[i] - ‘a‘; 57 if(!ch[now][c]) return n; 58 now = ch[now][c]; 59 } 60 if(vis[now]) return vis[now]; 61 int Max = nd[now][0] - 1; 62 for(int i = 1; i < (int)nd[now].size(); ++i) Max = max(Max, nd[now][i] - nd[now][i - 1] - 1); 63 return vis[now] = max(Max, n - nd[now][nd[now].size() - 1]); 64 } 65 66 char s[maxn]; 67 68 int main() 69 { 70 freopen("word.in", "r", stdin); 71 freopen("word.out", "w", stdout); 72 n = read(); m = read(); 73 for(int i = 1; i <= n; ++i) {scanf("%s", s); insert(i, s);} 74 for(int i = 1; i <= m; ++i) 75 { 76 scanf("%s", s); 77 write(query(s)); enter; 78 } 79 return 0; 80 }
然而今天不知是谁想出了更强的算法。就是每一个节点维护一个Max[i]:代表结点 i能达到的最长连续 0的长度,las[i]代表trie树上最后经过结点 i 的是第几个字符串。las[i]当然是为了求Max[i]服务的,在建树过程中,用当前的字符串id,就可以更新Max[i] = max(Max[i], id - las[i] - 1),然后las[i] = id。
这样就优化到了O(∑lent)预处理,O(∑lens)查询。
优化后的代码:
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<vector> 9 #include<stack> 10 #include<queue> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(‘ ‘) 14 #define Mem(a) memset(a, 0, sizeof(a)) 15 typedef long long ll; 16 typedef double db; 17 const int INF = 0x3f3f3f3f; 18 const db eps = 1e-8; 19 const int maxn = 5e6 + 5; 20 inline ll read() 21 { 22 ll ans = 0; 23 char ch = getchar(), last = ‘ ‘; 24 while(!isdigit(ch)) {last = ch; ch = getchar();} 25 while(isdigit(ch)) {ans = ans * 10 + ch - ‘0‘; ch = getchar();} 26 if(last == ‘-‘) ans = -ans; 27 return ans; 28 } 29 inline void write(ll x) 30 { 31 if(x < 0) x = -x, putchar(‘-‘); 32 if(x >= 10) write(x / 10); 33 putchar(x % 10 + ‘0‘); 34 } 35 36 int n, m; 37 int ch[maxn][3], las[maxn], Max[maxn], tot = 0; 38 void insert(int id, char* s) 39 { 40 int m = strlen(s), now = 0; 41 for(int i = 0; i < m; ++i) 42 { 43 int c = s[i] - ‘a‘; 44 if(!ch[now][c]) ch[now][c] = ++tot; 45 now = ch[now][c]; 46 Max[now] = max(Max[now], id - las[now] - 1); 47 las[now] = id; 48 49 } 50 } 51 int query(char *s) 52 { 53 int m = strlen(s), now = 0; 54 for(int i = 0; i < m; ++i) 55 { 56 int c = s[i] - ‘a‘; 57 if(!ch[now][c]) return n; 58 now = ch[now][c]; 59 } 60 return max(Max[now], n - las[now]); 61 } 62 63 char s[maxn]; 64 65 int main() 66 { 67 freopen("word.in", "r", stdin); 68 freopen("word.out", "w", stdout); 69 n = read(); m = read(); 70 for(int i = 1; i <= n; ++i) {scanf("%s", s); insert(i, s);} 71 for(int i = 1; i <= m; ++i) 72 { 73 scanf("%s", s); 74 write(query(s)); enter; 75 } 76 return 0; 77 }
最后吐槽:最惨的还是MLE,算是吸取个教训了……
标签:技术分享 trie树 搜索 tac 初始 add bfs 理解 size
原文地址:https://www.cnblogs.com/mrclr/p/9574564.html