zoukankan      html  css  js  c++  java
  • 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,算是吸取个教训了……

  • 相关阅读:
    ASP.NET MVC随想录——锋利的KATANA
    ASP.NET MVC随想录——漫谈OWIN
    Notepad++ 64位 插件管理
    C#实现按键精灵的'找图' '找色' '找字'的功能
    http://www.haolizi.net/example/view_2380.html
    C# 关于在原图中寻找子图片坐标的类
    WebBrowser控件默认使用IE9,IE10的方法
    Springboot---后台导出功能,easyExcel
    vue---EleElement UI 表格导出功能
    vue---提取公共方法
  • 原文地址:https://www.cnblogs.com/mrclr/p/9574564.html
Copyright © 2011-2022 走看看