Wannafly挑战赛9: B. 数一数

链接:https://www.nowcoder.com/acm/contest/71/B
来源:牛客网

题目描述

设s,t为两个字符串,定义f(s,t) = t的子串中,与s相等的串的个数。如f("ac","acacac")=3, f("bab","babab")=2。现在给出n个字符串,第i个字符串为s i。你需要对 ,求出 ,由于答案很大,你只需要输出对 998244353取模后的结果。

输入描述:

第一行一个整数n。
接下来n行每行一个仅由英文字母构成的非空字符串,第i个字符串代表si

输出描述:

共n行,第i行输出对 998244353取模的结果。


对于对于字符串s和t,当前仅当s==t时f(s, t)和f(t, s)都为1,否则一定有一个是0

答案求的是连乘,所以一旦某个f(s, t)是0,那么最后串s的答案就一定为0

对于num个完全相同的串s,可以把它们缩成1个,这样若f(t, s)==x,那么s对t的贡献就是x^num

去重后每计算一个f(s, t)都一定会得出一个串的答案(为0)所以最后复杂度为O(len+n)


#include<stdio.h>
#include<string>
#include<string.h>
#include<map>
using namespace std;
map<string, int> p;
#define mod 998244353
#define LL long long
LL ans[1000005];
int net[2000005], id[1000005];
typedef struct
{
	int len, sum;
	char *str;
}Str;
Str s[1000005];
char str[2000005];
LL Pow(LL a, LL b)
{
	LL ans = 1;
	while(b)
	{
		if(b%2)
			ans = ans*a%mod;
		a = a*a%mod;
		b /= 2;
	}
	return ans;
}
int Kmp(char *b, char *a)
{
	int i, j, n, m, ans;
	i = j = 1, ans = 0;
	n = strlen(a+1);
	m = strlen(b+1);
	while(i<=n)
	{
		if(a[i]==b[j])
		{
			if(j==m)
			{
				ans++;
				j = net[j+1];
				i++;
			}
			else
				i++, j++;
		}
		else
		{
			j = net[j];
			if(j==0)
				i++, j = 1;
		}
	}
	return ans;
}
int Getnext(char *b, char *a)
{
	int i, j, m;
	i = 1, j = 0;
	net[1] = 0;
	m = strlen(b+1);
	while(i<=m)
	{
		if(j==0 || b[i]==b[j])
		{
			i++, j++;
			if(b[i]==b[j])
				net[i] = net[j];
			else
				net[i] = j;
		}
		else
			j = net[j];
	}
	return Kmp(b, a);
}
int main(void)
{
	int n, i, j, now;
	scanf("%d", &n);
	for(i=1;i<=n;i++)
	{
		scanf("%s", str+1);
		if(p.count(str+1))
		{
			id[i] = p[str+1];
			s[id[i]].sum++;
			continue;
		}
		p[str+1] = i;
		s[i].sum = 1;
		s[i].len = strlen(str+1);
		s[i].str = new char[s[i].len+5];
		strcpy(s[i].str+1, str+1);
	}
	for(i=1;i<=n;i++)
		ans[i] = 1;
	for(i=1;i<=n;i++)
	{
		if(ans[i]==0 || id[i])
			continue;
		for(j=1;j<=n;j++)
		{
			if(i==j || id[j])
				continue;
			now = Getnext(s[i].str, s[j].str);
			if(now==0)
			{
				ans[i] = 0;
				break;
			}
			else
			{
				ans[j] = 0;
				ans[i] = ans[i]*Pow(now, s[j].sum)%mod;
			}
		}
	}
	for(i=1;i<=n;i++)
	{
		if(id[i]!=0)
			printf("%lld\n", ans[id[i]]);
		else
			printf("%lld\n", ans[i]);
	}
	return 0;
}
/*
5
a
a
a
aa
aa
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值