HDOJ多校联合第六场

先一道一道题慢慢补上,

1009.题意,一棵N(N<=50000)个节点的树,每个节点上有一个字母值,给定一个串S0(|S0| <=30),q个询问,(q<=50000),每次询问经过两个点u,v之间的路径上的字母构成字符串S,问S0在S中作为序列出现了多少次。

分析:对于每次询问需要知道其LCA,设w = LCA(u, v),可以用tarjan处理出来,或者倍增法也行。然后w会将S0分成两部分,记做S1,S2,然后分别考虑S1在u->w的路径出现次数,以及S2在v->w出现的次数。

S1(x) = S0[1....x],1<=x<=|S0|.

以S1为例,需要预处理出来u到根节点的路径上对应S0[i,j]序列出现的次数,设为dp1[u][i][j],然后S1(x)在u->w出现的次数记为t1[x],那么

t1[x] = dp1[u][1][x] - sum{t1[a-1]*dp1[fa[w]][a][x]} (1<=a<=x)

而dp1[u][1][x] 可以在tarjan求LCA时候预处理出来,转移dp1[u][i][j] = dp1[fa[u]][i][j] + (nd[u] == S0[i])*dp1[fa[u]][i+1][j];

对于S2也是可以同样考虑的。

注意:占用内存很大,需要用16位节省内存,dfs的话还需要扩栈,实现时发现不能随便用unsigned short,因为变成负数的话会相当于mod 2^16这个是会导致WA的。

代码:

  1 #pragma comment(linker, "/STACK:16777216")
  2 #include <cstdio>
  3 #include <iostream>
  4 #include <cstring>
  5 #include <string>
  6 #include <cstdlib>
  7 #include <algorithm>
  8 #include <vector>
  9 #include <queue>
 10 #include <map>
 11 #include <set>
 12 #define in freopen("solve_in.txt", "r", stdin);
 13 #define Rep(i, base, n) for(int i = (base); i < n; i++)
 14 #define REP(i, n) for(int i = 0; i < (n); i++)
 15 #define  VREP(i, n, base) for(int i = (n); i >= (base); i--)
 16 #define SET(a, n) memset(a, (n), sizeof(a));
 17 #define pb push_back
 18 #define mp make_pair
 19 
 20 using namespace std;
 21 typedef vector<unsigned  short> VI;
 22 typedef pair<unsigned  short, unsigned  short> PII;
 23 typedef vector<PII> VII;
 24 typedef long long LL;
 25 
 26 const int maxn = 50000 + 10;
 27 const int maxm = 33;
 28 const int M = 10007 ;
 29 
 30 short dp1[maxn][maxm][maxm], dp2[maxn][maxm][maxm];
 31 bool vis[maxn];
 32 int len;
 33 char s[maxm], nd[maxn];
 34 unsigned short pa[maxn];
 35 
 36 VI g[maxn];
 37 unsigned  short lca[maxn];
 38 VII que[maxn];
 39 VII qq;
 40 
 41 unsigned  short findset(unsigned  short x) {
 42     return x == pa[x] ? x : pa[x] = findset(pa[x]);
 43 }
 44 
 45 void init(int n) {
 46     qq.clear();
 47     REP(i, n+1) {
 48         que[i].clear();
 49         g[i].clear();
 50         vis[i] = false;
 51         REP(j, maxm) REP(k, maxm) {
 52             dp1[i][j][k] = 0, dp2[i][j][k] = 0;
 53             if(j > k)
 54                 dp1[i][j][k] = 1;
 55             if(j < k)
 56                 dp2[i][j][k] = 1;
 57         }
 58     }
 59 }
 60 int n, m;
 61 short t1[maxm], t2[maxm];
 62 void tarjan(int u, int fa) {
 63     pa[u] = u;
 64     if(!fa) {
 65         Rep(i, 1, len+1)
 66         if(s[i] == nd[u]) {
 67             dp1[u][i][i] = dp2[u][i][i] = 1;
 68         }
 69     } else {
 70         int v = u;
 71         u = fa;
 72         Rep(i, 1, len+1) Rep(j, 1, len+1) {
 73             if(i >= j) {
 74                 dp2[v][i][j] = (dp2[v][i][j] + dp2[u][i][j] + (nd[v] == s[i])*(dp2[u][i-1][j]))%M;
 75             }
 76             if(dp2[v][i][j] < 0)
 77                 dp2[v][i][j] += M;
 78             if(i <= j) {
 79                 dp1[v][i][j] = (dp1[v][i][j] + dp1[u][i][j] + (nd[v] == s[i])*(dp1[u][i+1][j]))%M;
 80             }
 81             if(dp1[v][i][j] < 0)
 82                 dp1[v][i][j] += M;
 83         }
 84         u =v;
 85     }
 86     vis[u] = true;
 87     REP(i, g[u].size()) {
 88         int v = g[u][i];
 89         if(v == fa)
 90             continue;
 91         tarjan(v, u);
 92         pa[v] = u;
 93     }
 94     REP(i, que[u].size()) {
 95         int v = que[u][i].first;
 96         int id = que[u][i].second;
 97         if(!vis[v])
 98             continue;
 99         lca[id] = findset(v);
100     }
101 }
102 void solve() {
103     REP(ii, m) {
104         int w = lca[ii];
105         int u = qq[ii].first;
106         int v = qq[ii].second;
107         if(u == v) {
108             printf("%d
", len == 1 && s[1] == nd[u]);
109             continue;
110         }
111         SET(t1, 0);
112         SET(t2, 0);
113         t1[0] = t2[len+1] = 1;
114         if(w != u) {
115             Rep(i, 1, len+1) {
116                 int tmp = 0;
117                 Rep(x, 1, i+1) {
118                     tmp = (tmp + ((LL)t1[x-1]*dp1[w][x][i])%M)%M;
119                 }
120                 t1[i] = (dp1[u][1][i]-tmp)%M;
121                 if(t1[i] < 0)
122                     t1[i] += M;
123             }
124         }
125         if(w != v) {
126             VREP(i, len, 1) {
127                 int tmp = 0;
128                 VREP(x, len, i) {
129                     tmp = (tmp + ((LL)t2[x+1]*dp2[w][x][i])%M)%M;
130                 }
131                 t2[i] = (dp2[v][len][i] - tmp)%M;
132                 if(t2[i] < 0)
133                     t2[i] += M;
134             }
135         }
136         int ans = 0;
137         REP(i, len+1) {
138             if(s[i] == nd[w])
139                 ans = (ans + ((LL)t1[i-1]*t2[i+1])%M)%M;
140             ans = (ans + ((LL)t1[i]*t2[i+1])%M)%M;
141             if(ans < 0)
142                 ans += M;
143         }
144         if(ans < 0)
145             ans += M;
146         printf("%d
", ans);
147     }
148 }
149 int main() {
150     
151     int T;
152     for(int t = scanf("%d", &T); t <= T; t++) {
153         scanf("%d%d", &n, &m);
154         init(n);
155         REP(i, n-1) {
156             int u, v;
157             scanf("%d%d", &u, &v);
158             g[u].pb(v);
159             g[v].pb(u);
160         }
161         s[0] = '';
162         scanf("%s%s", nd+1, s+1);
163         len = strlen(s+1);
164         REP(i, m) {
165             int u, v;
166             scanf("%d%d", &u, &v);
167             qq.pb(mp(u, v));
168             que[u].pb(mp(v, i));
169             que[v].pb(mp(u, i));
170         }
171         tarjan(1, 0);
172         solve();
173     }
174     return 0;
175 }
View Code
原文地址:https://www.cnblogs.com/rootial/p/3899109.html