18.9.2开学模拟题解

好久没有模拟了,然后一模拟就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 }
View Code

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 }
View Code

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 }
View Code

  然而今天不知是谁想出了更强的算法。就是每一个节点维护一个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 }
View Code

最后吐槽:最惨的还是MLE,算是吸取个教训了……

原文地址:https://www.cnblogs.com/mrclr/p/9574564.html