2020杭电多校第四场 1005 Equal Sentences

本文介绍了一种利用动态规划(DP)算法解决几乎相等字符串序列计数问题的方法。通过定义状态dp[i][0/1],分别表示前i位中是否与前一位进行交换的方案数,实现了对特定条件下序列变化的有效统计。文章详细阐述了状态转移方程,并提供了C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

在这里插入图片描述
题目链接

题目大意给定一个字符串序列,求其有多少个“几乎相等”的序列。

题目中对“几乎相等”的定义为:

  1. 两个字符串序列中每种单词出现的数量需要相同
  2. 每种单词的第i个在两个序列中出现的位置相差不能超过1

根据这个定义,序列本身就是一个“几乎相等”序列。除此之外,任意交换原序列两个相邻的元素,得到的序列是一个“几乎相等”序列。但是参与交换的两个元素不能相同且其中不能有已经参与过交换的

基于这个规则,我们可以使用dp来进行状态统计。

我们设状态 dp[i][0/1]表示前i位的方案数,0代表与上一个进行交换,1代表不与上一个进行交换。

于是不难得出下列转移方程:

d p [ i ] [ 0 ] = { 0 ( s t r [ i ] = s t r [ i − 1 ] ) d p [ i − 1 ] [ 1 ] ( s t r [ i ] ≠ s t r [ i − 1 ] ) dp[i][0] = \left\{\begin{matrix} 0 (str[i] = str[i - 1]) \\ dp[i - 1][1](str[i] ≠str[i-1]) \end{matrix}\right. dp[i][0]={0(str[i]=str[i1])dp[i1][1](str[i]=str[i1])
d p [ i ] [ 1 ] = d p [ i − 1 ] [ 0 ] + d p [ i − 1 ] [ 1 ] dp[i][1]= dp[i - 1][0] + dp[i - 1][1] dp[i][1]=dp[i1][0]+dp[i1][1]
不要忘记初始化:
d p [ 1 ] [ 0 ] = 0 dp[1][0]=0 dp[1][0]=0
d p [ 1 ] [ 1 ] = 1 dp[1][1]=1 dp[1][1]=1

答案就是:
a n s = d p [ n ] [ 0 ] + d p [ n ] [ 1 ] ans=dp[n][0]+dp[n][1] ans=dp[n][0]+dp[n][1]
不要忘记取模!!!!

代码:

#include<iostream>
#include<cstring>
using namespace std;
const int N = 1e5 + 50;
const int mo = 1e9 + 7;
long long dp[N][2];
char a[N][20];
int n,T;
int main(){
	for(cin >> T;T;T--){
		cin >> n;
		for(int i = 1;i <= n;i++){
			cin >> a[i];
		}
		dp[1][0] = 0;
		dp[1][1] = 1;
		for(int i = 2;i <= n;i++){
			if(!strcmp(a[i],a[i - 1])){
				dp[i][0] = 0;
			}else{
				dp[i][0] = dp[i - 1][1];
			}
			dp[i][1] = (dp[i - 1][0] + dp[i - 1][1]) % mo;
		}
		cout << (dp[n][0] + dp[n][1]) % mo<< endl;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值