题意:长的我都不想看… 给定你一个NxN的矩阵,矩阵中的元素有#和小写字母,#代表障碍。然后给定你m个询问,每个询问都含有一个字符串和值。然后从矩阵中截取子串,子串的截取规则是水平方向上顶到障碍的和竖直方向上顶到障碍的所有子串,然后问你这些子串是否全部存在于我询问的m个字符串中,若存在的话输出他们的总和值,否则输出-1。
思路:题目最后的输入保证的是询问的范围大小,从这点都很容易想到应该对这m个串操作,把这m个串先插入到字典树中,然后每次枚举合法的截取子串看是否存在于字典树即可。
用到的插入和查询都是基本操作,没有什么坑点。
代码:
#include <bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
typedef long long ll;
const int MAXN = 1e3 + 7;
const int N = 4e6 + 7;
char mp[MAXN][MAXN];
char str[MAXN],t[MAXN];
int n,m;
int trie[N][26],idx,val[N];//题目中说m个单词的总长度不会超过4e6
void insert(char *s,int x){
int p = 0,len = strlen(s);
for(int i = 0;i < len;i ++){
int ch = s[i] - 'a';
if(!trie[p][ch]) trie[p][ch] = ++idx;
p = trie[p][ch];
}
val[p] = x;
}
int query(char *s){
int p = 0,len = strlen(s);
for(int i = 0;i < len;i ++){
int ch = s[i] - 'a';
p = trie[p][ch];
if(!p) return -1;
}
if(val[p]) return val[p];
else return -1;
}
void init(){
for(int i = 0;i <= idx;i ++){
memset(trie[i],0,sizeof(trie[i]));
val[i] = 0;
}
idx = 0;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
init();
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i ++){
scanf("%s",mp[i]+1);
}
while(m--){
int x;
scanf("%s%d",str,&x);
insert(str,x);
}
int flag = 0;ll sum = 0;
for(int i = 1;i <= n;i ++){
for(int j = 1;j <= n;j ++){
int len = 0;
if(mp[i][j] == '#') continue;
while(mp[i][j] != '#' && j <= n){
t[len++] = mp[i][j];
j++;
}
t[len] = '\0';
int ans = query(t);
if(ans == -1) flag = 1;
else sum += ans;
}
//if(flag) break;
}
for(int j = 1;j <= n;j ++){
for(int i = 1;i <= n;i ++){
int len = 0;
if(mp[i][j] == '#') continue;
while(mp[i][j] != '#' && i <= n){
t[len++] = mp[i][j];
i++;
}
t[len] = '\0';
int ans = query(t);
if(ans == -1) { flag = 1; }
else sum += ans;
}
//if(flag) break;
}
if(flag) printf("-1\n");
else printf("%lld\n",sum);
}
return 0;
}