Nun Heh Heh Aaaaaaaaaaa 动态规划

Vasily Tadokorov is a stringologist. He thinks a string is fragrant if it can be divided into two parts ― \texttt{nunhehheh}nunhehheh as the prefix and a number of (excluding 00) \texttt{a}a as the suffix. For example, \texttt{nunhehhehaaaaaa}nunhehhehaaaaaa is fragrant, but \texttt{nunhehheh}nunhehheh and \texttt{nunhehhehoooaaa}nunhehhehoooaaa are not fragrant.

Today Vasily Tadokorov has some strings consisting of lowercase English letters. For each string, he wants to know how many subsequences of this string are fragrant. A string aa is a subsequence of a string bb if aa can be obtained from bb by deletion of several (including 00) characters.

Input

The first line contains an integer T\ (1 \leq T \leq 1000)T (1≤T≤1000), denoting the number of strings.

Each of the next TT lines contains a string S\ (1 \leq |S| \leq 10^5)S (1≤∣S∣≤105) consisting of lowercase English letters.

The total length of the strings in the input will not exceed 10^6106.

Output

For each of the given TT strings, output the answer modulo 998244353998244353.

Sample Input

2
nunhehhehahaahahahahahahaahaahahahahha
nunhehhehhehhahaahahahaahaahahaaaahaa

Sample Output

114514
1919810

给定一个字符串 求子串为nunhehhehaaaa.....的个数(a的个数不能为零) 

用动态规划

给定的字符串为s,nunhehheh为字符串p dp[i][j](i 为s串的下标 j 为p串的下标) 的值为在s的第一个字符到第i个字符的字符串中 在p的第一个字符到第j个字符的字符串 的个数.

如dp[i][9] 表示 在s的第一个字符到第i个字符中 字符串nunhehheh的个数

如果s[i] == p[j] 那么有两种选择情况 把s[i] 加入 p中从第一个字符到第j-1个字符的子串里 这个子串的个数就是dp[i-1][j-1]  ( 当j == 1 时 这个子串就是空串 这样就是把s[i] 当做一个新的串 所以应该把dp[i-1][0] 初始化为一)

也可以选择不加 就是dp[i-1][j]

那么dp[i][j] = dp[i-1][j-1] + dp[i-1][j]

如果s[i] != p[j] 只能选择不加 所以dp[i][j] = dp[i-1][j]

初始化 dp[i][0] = 1 以及s串和p串刚开始匹配的字符串的值都为一

为了方便在s串和p串的前面加上0 让字符串的下标从一开始

接下来计算nunhehheh串后面a的个数 用a的个数就可计算出子串的数目 ( 用排列组合 

和二项式 )如果a的个数有n个 那子串的个数就是2的n次方减1 (用快速幂计算2的n次方)

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5+10,MOD = 998244353;
typedef long long ll;
ll dp[MAXN][10];
ll ksm(ll base,ll power)
{
	ll ans = 1;
	while(power){
		if(power & 1)
			ans = ans * base % MOD;
		power = power >> 1;
		base = base * base % MOD;
	}
	return ans;
}
int main()
{
	string p = "0nunhehheh";
	int n;
	cin >> n;
	for(int k = 0;k < n;k++){
		memset(dp,0,sizeof(dp));
		string s = "0",str;
		cin >> str;
		s += str;
		int len = s.length(),num_a = 0;
		for(int i = 0;i < len; i++)
			dp[i][0] = 1;
		for(int i = 1;i < 10; i++)
			if(s[i] == p[i])
				dp[i][i] = 1;
			else
				break;
		for(int i = 1;i < len; i++){
			for(int j = 1;j < 10; j++){
				if(i-1 >= j)
					if(s[i] == p[j])
						dp[i][j] = (dp[i-1][j-1] + dp[i-1][j]) % MOD;
					else
						dp[i][j] = dp[i-1][j];
			}
			if(s[i] == 'a') num_a++;
		}
		ll res = 0;
		for(int i = 1;i < len;i++){
			if(s[i] == 'a') num_a--;
			res = (res+((dp[i][9] - dp[i-1][9])%MOD+MOD)%MOD * (ksm(2,num_a) -1)) % MOD;
		}
		cout << res << "\n";
	}
	return 0;
 } 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值