Unhappy Hacking II

本文介绍了一种计算特定长度字符串生成方案数目的算法,通过动态规划方法解决键盘操作(输入数字与退格)的问题。文章详细解释了状态转移方程,并提供了C++实现代码。

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

http://icpc.upc.edu.cn/problem.php?cid=1696&pid=10 

 应该是有O(n)的做法的,但是目前来说我只会O(n2)O(n2)的做法,讲一下O(n2)的吧。

  记f[i][j]为按了i下键盘之后产生了长度为j的串的方案数,初始f[0][0]=1。

  对于某个f[i][j],要么按一次数字键(0或者1)变成f[i + 1][j + 1],要么按一次退格键变成f[i + 1][j - 1],也就是说,每一个f[i][j]只会对两个状态产生影响,但是一个f[i][j]会被很多状态影响,显然从i推i + 1会简单很多,则有:

f[i + 1][j + 1] += 2 * f[i][j]
f[i + 1][max(j - 1, 0)] += f[i][j]
  注意j = 0的时候相当于屏幕上此时没有字符,此时按退格键虽然不会改变字符,但仍然是一个有效状态,所以取max(j - 1, 0)。

  这样仅仅是得到了按i下键盘时得到了长度为j的串的方案数,但是题目里所给的串是一个特定的串,是所有长度为j的串的其中之一,又因为长度为j的串中每个字符要么是0要么是1,总共有2 j2 j种串,所以按n下得到某个长度为len的串的方案数应为

f[n][len]/2^j。

#include<cstdio>
#include<iostream>
#include<cstring>
#define N 5005
#define p 1000000007
#define ll long long
using namespace std;
int n,l,i,j,k,a[N][N];
char c[N];
ll ksm(ll a,ll b){
	ll s=1;
	while (b){
		if (b&1){
			s=s*a%p;
		}
		a=a*a%p;
		b=b>>1;
	}
	return s;
} 
int main() {
	scanf("%d",&n);
	scanf("%s",c);
	l=strlen(c);
	a[0][0]=1;
	for (i=0; i<=n; i++) {
		for (j=0; j<=i; j++) {
			a[i+1][j+1]=(1ll*a[i][j]*2%p+a[i+1][j+1])%p;
			a[i+1][max(j-1,0)]=(a[i][j]+a[i+1][max(j-1,0)])%p;
		}
	}
	printf("%d\n",ksm(ksm(2,l),p-2)*a[n][l]%p);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值