#倍增优化dp#CH 5702 Count The Repetitions

博客围绕CH 5702 Count The Repetitions题目展开,分析是求最小的m,使conn(s2,n2∗m)=conn(s1,n1),其上界为n1∗len1/n2,采用倍增拼凑方法,设dp[i][j]表示从s1[j]开始生成2i个s2所需最少字符,最后给出解题代码。

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

题目链接


分析

可以发现题目就是求最小的 m m m,使 c o n n ( s 2 , n 2 ∗ m ) = c o n n ( s 1 , n 1 ) conn(s2,n2*m)=conn(s1,n1) conn(s2,n2m)=conn(s1,n1)
它肯定会有一个上界也就是 n 1 ∗ l e n 1 / n 2 n1*len1/n2 n1len1/n2,然而这个上界还是很大,考虑用倍增拼凑
d p [ i ] [ j ] dp[i][j] dp[i][j]表示从 s 1 [ j ] s1[j] s1[j]开始,能生成 2 i 2^i 2i s 2 s2 s2至少需要多少字符
i = 0 i=0 i=0时就是暴力对吧,之后 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + d p [ i − 1 ] [ ( j + d p [ i − 1 ] [ j ] − 1 )   m o d   l e n 1 + 1 ] dp[i][j]=dp[i-1][j]+dp[i-1][(j+dp[i-1][j]-1)\bmod len1+1] dp[i][j]=dp[i1][j]+dp[i1][(j+dp[i1][j]1)modlen1+1],正确性显然、
嗯,然后就是拼凑


代码

#include <cstdio>
#include <cstring>
#include <cmath>
#define rr register
using namespace std;
typedef unsigned uit;
char s1[101],s2[101]; uit k1,k2,dp[31][101];
signed main(){
	while (scanf("%s%u%s%u",s2+1,&k2,s1+1,&k1)==4){
		rr uit len1=strlen(s1+1),len2=strlen(s2+1),flag=0;
		for (rr uit i=1;i<=len1;++i){
			rr uit p=0,t1=i,t2=1;
			while (p<=len2){
				if (s1[t1]==s2[t2]&&++t2>len2) break;
				if (++t1>len1) ++p,t1=1;
			}
			if (p>len2){flag=1; printf("0\n"); break;}
			dp[0][i]=p*len1+t1-i+1;
		}
		if (flag) continue;
		rr uit lg=log2(k1*len1/len2)+1;
		for (rr uit i=1;i<=lg;++i)
		for (rr uit j=1;j<=len1;++j)
		dp[i][j]=dp[i-1][j]+dp[i-1][(j+dp[i-1][j]-1)%len1+1];
		rr uit t=0,ans=0;
		for (rr int i=lg;i>=0;--i)
		if (t+dp[i][t%len1+1]<=len1*k1)
			t+=dp[i][t%len1+1],ans|=1<<i;
		printf("%u\n",ans/k2);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值