2020ZJCPC--C. Crossword Validation(字典树)

A crossword is a word puzzle that usually takes the form of a square or a rectangular grid of white- and black-shaded cells. The game’s goal is to fill the white cells with letters, forming words or phrases, by solving clues, which lead to the answers. The answer words and phrases are typically placed in the grid from left to right and from top to bottom. The shaded cells are used to separate the words or phrases. Crossword grids such as those appearing in most North American newspapers and magazines feature solid areas of white cells. Every letter is checked (i.e. is part of both an “across” word and a “down” word) and usually each answer must contain at least three letters. In such puzzles, shaded cells are typically limited to about one-sixth of the total. Crossword grids elsewhere, such as in Britain, South Africa, India and Australia, have a lattice-like structure, with a higher percentage of shaded cells, leaving about half the letters in an answer unchecked. For example, if the top row has an answer running all the way across, there will often be no across answers in the second row.

Crossword puzzles have a long history. The title for the world’s first crossword puzzle is disputed, but most people believe the crossword puzzle is invented in the 19th century. With the emergence of personal computers, more and more crossword puzzles are distributed online instead of on newspapers and books. Software that aids in creating and solving crossword puzzles has been written since at least 1976. In this problem, you are to write a program that checks if a solution for a crossword puzzle is valid. Note that the rules of the puzzle in this problem, which is described in the next paragraph, may differ from the real-world ones.

You are given a completed crossword puzzle on a N × N grid. Each cell is either a white cell filled with a letter or a black cell. You are also given a dictionary of M distinct words, where each word has a score associated with it. A horizontal candidate word in the grid is a continuous string of letters on the same row of the grid that can’t be extended. Formally, this means that the cell to the left of the leftmost cell of the candidate word either doesn’t exist or is a black cell, and the same goes for the cell to the right of the rightmost cell. Vertical candidate words are defined similarly, except that the letters are on the same column. Candidate words are read from left to right for horizontal words or from top to bottom for vertical words. The crossword puzzle is valid if and only if each candidate word is present in the given dictionary. The score of a valid puzzle is the sum of the scores in the dictionary associated with each candidate word. Note that two or more candidate words may be the same. In this case, the score of that word is added multiple times accordingly. Your program must determine the score of the solution, or report that it is not valid.

Input

The input contains multiple cases. The first line of the input contains a single positive integer T, the number of cases. For each case, the first line of the input contains two integers N, M (1 ≤ N ≤ 1 000, 1 ≤ M ≤ 4 × 10^6 ), the size of the grid and the number of words in the dictionary. The following N lines each contain a string of length N, where each character is either a lowercase English letter or ‘#’. If the j-th character of the i-th string is ‘#’, then the cell located in the intersection of the i-th row and the j-th column is a black cell. Otherwise, this character denotes the letter filled in that cell. The following M lines each contain a non-empty string consisting of only lowercase English letters, and a positive integer, denoting a word in the dictionary and its score. It is guaranteed that those M words are pairwise distinct, the length of each word doesn’t exceed N, and the score of each word doesn’t exceed 10^9 . It is guaranteed that the sum of N2 over all cases doesn’t exceed 4 × 10^6 , and the sum of the lengths of all words in the dictionary over all cases doesn’t exceed 4 × 10^6 .

Output

For each case, print a single integer in a single line, the score of the crossword solution given in the input if it is valid. If the solution is not valid, print −1 instead.

Input

2
2 4
ab
#d
ab 1
a 2
d 3
bd 4
2 4
ab
c#
ab 5
ca 2
b 6
c 7

Output

10
-1

题意:如果矩形行和列中完整字符串均在m个字符串中出现过,那么就计算出贡献和,否则输出-1

注意:这题输入字符串量大,需要cin优化,不然会T

解析:因为要求的是矩形中的字符串全部在m个字符串出现过,因此我们应该是把m个字符串插入字典树,而不是将矩形中的字符串插入(可以是可以,但是后续还需判断是否全部出现,太过麻烦),然后每次询问如果存在就累加和,否则输出-1即可

#include <bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
const int N=1005,M=4e6+5;
typedef long long ll;
int son[M][26],idx,n,m;
ll cnt[M];
char a[N][N];//保存矩形
void add(string x,ll v)
{
	int p=0;
	for(int i=0;i<x.size();i++)
	{
		int u=x[i]-'a';
		if(!son[p][u]) son[p][u]=++idx;
		p=son[p][u];
	}
	cnt[p]+=v;//该节点的贡献值是v
}
ll query(string x)
{
	int p=0;
	for(int i=0;i<x.size();i++)
	{
		int u=x[i]-'a';
		if(!son[p][u]) return 0;
		p=son[p][u];
	}
	return cnt[p];
}
void solve()
{
	for(int i=0;i<=idx;i++)//多组需要初始化
	{
		memset(son[i],0,sizeof son[i]);
		cnt[i]=0;
	}
	idx=0;
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i]+1,a[i][n+1]='#',a[n+1][i]='#';
	n++;//因为制造边界,下方和右方延长一格
	while(m--)
	{
		string k;
		ll sum;
		cin>>k>>sum;
		add(k,sum);
	}
	ll ans=0;
	for(int i=1;i<=n;i++)//读行的字符串
	{
		string k;
		for(int j=1;j<=n;j++)
		{
			if(a[i][j]!='#') k+=a[i][j];
			else if(k!="")//读出字符串
			{
				ll c=query(k);
				if(c!=0) ans+=c;
				else
				{
					cout<<"-1"<<"\n";//不存在直接返回-1即可
					return;
				}
				k="";
			}
		}
	}
	for(int i=1;i<=n;i++)//读列的字符串
	{
		string k;
		for(int j=1;j<=n;j++)
		{
			if(a[j][i]!='#') k+=a[j][i];
			else if(k!="")
			{
				ll c=query(k);
				if(c!=0) ans+=c;
				else
				{
					cout<<"-1"<<"\n";
					return;
				}
				k="";
			}
		}
	}
	cout<<ans<<"\n";
}
int main()
{
	IOS;
	int t=1;
	cin>>t;
	while(t--) solve();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值