(2021ccpc网络赛重赛)Nun Heh Heh Aaaaaaaaaaa(dp)

本文介绍如何使用动态规划解决字符串问题,通过计算含有特定前缀nunhehheh且后面跟任意数量a的连续子串的总数。通过dp状态转移和取模操作优化计算过程。

题目链接:Problem - 7131 (hdu.edu.cn)

题目大概意思:给我们一个单词前缀nunhehheh,完整的合法子串需要前缀后面带若干个a(只能是a),数目不能是0,然后给我们一个字符串,问我们该字符串中有多少个满足题意的连续子串。

这道题目我们考虑dp求解,用dp[i][j]表示前i个字符中含有目标子串长度为j的方案数,下面直接进行dp就好,每找到一个合法的完整前缀,只需要乘以其后面a的贡献即可,注意取模。

下面是代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long ll;
const int N=1e5+10,mod=998244353;
ll f[N][10];
//f[i][j]表示前i个字符中目标子串长度为j的方案数 
char s[N];
ll qmi(ll a,ll b)
{
	ll ans=1;
	while(b)
	{
		if(b&1) ans=ans*a%mod;
		b>>=1;
		a=a*a%mod;
	}
	return ans;
}
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
  		scanf("%s",s+1);
  		int len=strlen(s+1);
 		//cnt记录a的个数 
  		ll ans=0,cnt=0;
	  	for(int i=1;i<=len;i++)
	  	{
	   		for(int j=1;j<=9;j++)
	    	f[i][j]=0;
	   		if(s[i]=='a')
	   		cnt++;
	  	}
		for(int i=1;i<=len;i++)
	  	{
	  		for(int j=1;j<=9;j++)//不要忘记一开始的赋值 
	  			f[i][j]=f[i-1][j];
	   		if(s[i]=='n')
	   		{
	    		f[i][1]=(f[i][1]+1)%mod;
	    		f[i][3]=(f[i][3]+f[i-1][2])%mod;
	   		}
	   		else if(s[i]=='u') f[i][2]=(f[i][2]+f[i-1][1])%mod;
	   		else if(s[i]=='h')
	   		{
	    		f[i][4]=(f[i][4]+f[i-1][3])%mod;
	    		f[i][6]=(f[i][6]+f[i-1][5])%mod;
	    		f[i][7]=(f[i][7]+f[i-1][6])%mod;
	    		f[i][9]=(f[i][9]+f[i-1][8])%mod;
	    		//注意此处f[i][9]有可能小于f[i-1][9]
	    		ans=(ans+((f[i][9]-f[i-1][9]+mod)%mod)*(qmi(2,cnt)-1))%mod;
	   		}
	   		else if(s[i]=='e')
	   		{
	    		f[i][5]=(f[i][5]+f[i-1][4])%mod;
	    		f[i][8]=(f[i][8]+f[i-1][7])%mod;
	   		}
	   		else if(s[i]=='a') cnt--;
	  	}
  		printf("%lld\n",ans);
 	}
 	return 0;
} 

不同年份的CCPC网络有不同的题目及解答: - 2018年CCPC网络:给一张竞图,对于所有的4元组,若为四元环贡献是1,有两个点的出度是2则贡献是 -1。先假设所有四元组都是四元环,这部分对答案的贡献是A(n,4)。对于非四元环的四元组,必然存在一个点出度是2,枚举每个度数>=2的点,其对答案的贡献是A(deg[i],2)*(n - 3)*4 ,所以最终答案ans = A(n,4) - ΣA(deg[i],2)*(n - 3)*4 ,这其实要求ΣC(deg[i],2),C(deg,2)=deg*(deg - 1)/2 ,当前度数为n,度数每增加1,对于这个点贡献增加n,可暴力连边跑费用流求解[^2]。 - 2021CCPC网络:发现规律,先将剩余的1或2或3构造出来,剩下的四个一组构造。代码实现如下: ```cpp #include<bits/stdc++.h> using namespace std; int main(void) { int t; cin>>t; while(t--) { int n; cin>>n; string ans; if(n%4==1) n=n-1,ans+="1"; else if(n%4==2) n=n-2,ans+="0001"; else if(n%4==3) n=n-3,ans+="01"; for(int i=1;i<=n/4;i++) ans+="1001"; cout<<ans.size()<<endl; cout<<ans<<endl; } return 0; } ``` 该题1009为Command Sequence,难度一般,知识点涉及前缀和与哈希[^4]。 - 2016年CCPC网络:一个星球一年有73天,另一个一年有137天,给定第n天,判断这一天是否同时是两个星球一年中的第一天,即判断n是否同时整除73和137,因n超大,使用紫书的大数模去一个较小的数的方法,代码如下: ```cpp #include <cstdio> #include <string> #include <cstring> #include <iostream> using namespace std; char n[10000010]; int m; int main(){ int m = 10001; int cas = 1; while(~scanf("%s",n)){ int len = strlen(n); int ans = 0; for(int i=0;i < len;i++){ ans = (int)(((long long)ans*10+n[i]-'0')%m); } printf("Case #%d: ",cas++); if (ans == 0) printf("YES\n"); else printf("NO\n"); } return 0; } ``` [^3]
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值