列表

详情


NC233977. [CERC2018]The ABCD Murderer

描述

Oscar enjoys watching crime movies very much. He admires all those villains for how creative some of them can get. He would like to show off some of his creativity, too. Sadly, he’s quite inexperienced and he is unable to come up with his own kind of a trick. So he would like to get inspired by some old trick. He always loved watching criminals cutting out the letters from newspapers and putting them together to form a ransom text. However, Oscar ain’t a total rip off so he came up with his own variant of this trick. He feels that putting the text together letter by letter is simply too boring and time consuming. So he decided to create his ransom note by cutting out whole words. 
Oscar bought several mainstream newspapers, therefore he has practically unlimited source of paper to cut the words from. He can cut out any particular word as many times as he wishes. However, he’s still limited by the set of words which appear in the newspapers. The trouble is that some words are just not used in the newspapers at all. To make his job a bit easier, he decided to erase all punctuation and all whitespace characters from the ransom note and ignore the case of characters. He also allows the cut-out words to overlap, as far as the overlapping parts contain the same text. Oscar now wonders how many words at minimum he has to cut out from the newspapers to put together the ransom note.

输入描述

The first input line contains an integer , the number of words found in the
newspapers. The next line contains the text of the ransom note. The text is not empty and
consists of lowercase English letters only. It is at most characters long.
Each of the next L lines contains one word appearing in the newspapers, in lowercase English
letters. None of these words is empty or longer than the text of the ransom note. All words
appearing in the newspapers are listed in the input at least once. Sum of lengths of all words is
not greater than
.

输出描述

Output the minimal number of words Oscar has to cut out from the newspapers to compose his ransom note. If it is not possible to compose the ransom note, print −1. Each word has to be counted as many times as it is physically cut out from a newspaper.

示例1

输入:

3
aaaaa
a
aa
aaa

输出:

2

示例2

输入:

5
abecedadabra
abec
ab
ceda
dad
ra

输出:

5

示例3

输入:

9
icpcontesticpc
international
collegiate
programming
contest
central
europe
regional
contest
icpc

输出:

3

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++ 解法, 执行用时: 131ms, 内存消耗: 57344K, 提交时间: 2022-03-01 17:21:04

#include<bits/stdc++.h>
using namespace std;
const int N = 300010;
const int T = 300010;
const int S = 300010;
char s[S],ss[S];
queue<int> q;
int dp[300010][20];
int n, tr[T][26], fail[T], tot, len[N], siz[T];
int ask(int l,int r)
{
	if(l>r) return 1e9+7;
	int k=log2(r-l+1);
	return min(dp[l+(1<<k)-1][k],dp[r][k]);//反向 
 } 
int main()
{
    int i,j,u;
    scanf("%d",&n);
    scanf("%s",ss+1);
    for (i=1;i<=n;i++)
    {
        scanf("%s",s);
        int l=strlen(s);
        for(u=0,j=0;s[j];++j)
        {
            int c = s[j] - 'a';
            if (!tr[u][c]) tr[u][c] = ++tot;
            u = tr[u][c];
        }
        len[u]=l;
    }
    for(int i=0;i<26;i++)if(tr[0][i]){fail[tr[0][i]]=0;q.push(tr[0][i]);}
    while (!q.empty())
    {
        int u = q.front();q.pop();
        len[u]=max(len[u],len[fail[u]]);
        //有些点不是结尾点 通过跳fail转移len 
        for (int i=0;i<26;i++)
        {
            if (tr[u][i])
            {
                fail[tr[u][i]] = tr[fail[u]][i];
                q.push(tr[u][i]);
            }
            else tr[u][i] = tr[fail[u]][i];
        }
    }
    memset(dp,0x3f3f3f3f,sizeof(dp));dp[0][0]=0;
    int l=strlen(ss+1);u=0;
    for(int i=1;i<=l;i++)
    {
       u=tr[u][ss[i]-'a'];
	   dp[i][0]=ask(i-len[u],i-1)+1;
	   for(int j=1;j<20;j++)
	   {
	   	 if(i-(1<<j)+1<0) break;
	   	 dp[i][j]=min(dp[i][j-1],dp[i-(1<<j-1)][j-1]);
		} 
	}
	printf("%d",dp[l][0]>1e9?-1:dp[l][0]);
    return 0;
}

C++(g++ 7.5.0) 解法, 执行用时: 130ms, 内存消耗: 57344K, 提交时间: 2023-05-07 11:00:12

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+11;
int n;
char s[N],ss[N];
int tr[N][26],len2[N],ne[N],cnt,dp[N][20];
queue<int>q;
void add(){
	int len=strlen(s),p=0;
	for(int j=0;j<len;j++){
		int v=s[j]-'a';
		if(!tr[p][v])tr[p][v]=++cnt;
		p=tr[p][v];
	}
	len2[p]=max(len2[p],len);
}
void kmp(){
	for(int i=0;i<26;i++){
		if(tr[0][i])q.push(tr[0][i]);
	}
	while(!q.empty()){
		int p=q.front();
		q.pop();
		len2[p]=max(len2[p],len2[ne[p]]);
		for(int i=0;i<26;i++){
			int j=tr[p][i];
			if(j){
				ne[j]=tr[ne[p]][i];
				q.push(j);
			}
			else tr[p][i]=tr[ne[p]][i];
		}
	}
}
int fx(int l,int r){
	if(l>r)return 1e9+7;
	int k=log2(r-l+1);
	return min(dp[r][k],dp[l+(1<<k)-1][k]);
}
int main(){
	scanf("%d%s",&n,ss+1);
	for(int i=1;i<=n;i++){
		scanf("%s",s);
		add();
	}
	kmp();
	int le=strlen(ss+1),p=1;
	memset(dp,0x3f,sizeof(dp));
	dp[0][0]=0;
	for(int i=1;i<=le;i++){
		int v=ss[i]-'a';
		p=tr[p][v];
		dp[i][0]=fx(i-len2[p],i-1)+1;
		for(int j=1;j<20;j++){
			if(i-(1<<j)+1<0)break;
			dp[i][j]=min(dp[i][j-1],dp[i-(1<<j-1)][j-1]);
		}
	}
	if(dp[le][0]>1e9)cout<<-1;
	else cout<<dp[le][0];
}

上一题