思路:建立字典树,然后dfs序列。
这题的主要难度在于怎么dfs计数的问题,字典树就是次要的难度。如何表示是不变,增加,删除这三种状态?
我们可以用一个指示性的指针来指向序列,用x来表示目前还可以增加删除的次数和。然后对于通过某种不变删除增加的组合形式最后到达的末节点表示为2,中间经过的节点表示为1。最后要注意的就是对于当前字符串搜索完之后要把vis数组清空。
// #pragma comment(linker, "/STACK:1024000000,1024000000") #include <iostream> #include <algorithm> #include <iomanip> #include <sstream> #include <string> #include <stack> #include <queue> #include <deque> #include <vector> #include <map> #include <set> #include <stdio.h> #include <string.h> #include <math.h> #include <stdlib.h> #include <limits.h> using namespace std; typedef long long LL; typedef unsigned long long ULL; typedef pair<int,int> ii; const int inf = 1 << 30; const int INF = 0x3f3f3f3f; const int MOD = 1e9 + 7; const int maxn = 3e6 + 10; const int segma_size = 26; class Tire{ private: int n; int size; int g[maxn][segma_size]; int vis[maxn], val[maxn]; int deep, ans; char s[15]; char str[15]; public: bool read(); void init(); void insert(char* str); int solve(char *str,int x); void dfs(int u,int d,int x); void clear(int u,int flag); void go(); }AC; int main() { // freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); while(AC.read()){ AC.init(); AC.go(); } return 0; } bool Tire::read(){ while(scanf("%d",&n)!=EOF){ return true; } return false; } void Tire::init(){ size = 1; val[0] = 0; memset(g[0], 0,sizeof g[0]); for (int i = 0;i < n;i++){ scanf("%s",str); insert(str); } } void Tire::insert(char* str){ int u = 0,len = strlen(str); for(int i=0;i<len;i++){ int v = str[i] - 'a'; if (g[u][v] == 0){ g[u][v] = size; val[size] = 0; memset(g[size], 0,sizeof g[size]); size++; } u = g[u][v]; val[u]++; } } int Tire::solve(char *str,int x){ ans = 0; deep = strlen(str); strcpy(s,str); dfs(0,0,x); clear(0,1); return ans; } void Tire::dfs(int u,int d,int x){ if (x < 0) return ; if (vis[u] == 0)vis[u] = 1; if (d == deep){ vis[u] = 2; return ; } int v = s[d] - 'a'; if (g[u][v]){ dfs(g[u][v],d+1,x); } dfs(u,d+1,x-1); for (int i = 0;i < segma_size;i++){ if (g[u][i]){ dfs(g[u][i],d,x-1);//增加 dfs(g[u][i],d+1,x-1);//删除 } } } void Tire::clear(int u,int flag){ if (vis[u] == 0)return; if (flag && vis[u] == 2){ ans += val[u]; flag = 0; } for (int i = 0;i < segma_size;i++){ if (g[u][i]) clear(g[u][i],flag); } vis[u] = 0; } void Tire::go(){ scanf("%d",&n); int d; for (int i = 1;i <= n;i++){ scanf("%s%d",str,&d); int t = solve(str,d); cout << t << endl; } }