【2016 ACM-ICPC 曼谷区域赛 Gym-101161 G】Binary Strings【矩阵快速幂】

题意:

01 01 01串,不包含两个连续的 1 1 1。要求给出满足下述三个条件的 01 01 01 串的个数。(答案模 1 e 9 + 7 1e9+7 1e9+7)

  • 01 01 01串长度在 [ L , R ] [L,R] [L,R] 之间 ( 1 ≤ L ≤ R ≤ 1 0 18 ) (1\leq L\leq R\leq 10^{18}) (1LR1018)
  • 01 01 01串长度是 K K K 的倍数 ( 1 ≤ K ≤ 1 0 9 ) (1\leq K\leq 10^9) (1K109)
  • 不包含连续两个 1 1 1 01 01 01

思路:

d p [ i ] [ 0 / 1 ] dp[i][0/1] dp[i][0/1] 表示长度为 i i i,末尾为 0 / 1 0/1 0/1的字符串个数。
d p [ i + 1 ] [ 0 ] = d p [ i ] [ 0 ] + d p [ i ] [ 1 ] , d p [ i + 1 ] [ 1 ] = d p [ i ] [ 0 ] dp[i+1][0]=dp[i][0]+dp[i][1],dp[i+1][1]=dp[i][0] dp[i+1][0]=dp[i][0]+dp[i][1],dp[i+1][1]=dp[i][0]

通过打表,可以发现 d p [ i ] dp[i] dp[i] 是一个斐波那契数列, d p [ 1 ] = 2 , d p [ 2 ] = 3 , d p [ 3 ] = 5 , d p [ n ] = d p [ n − 1 ] + d p [ n − 2 ] dp[1]=2,dp[2]=3,dp[3]=5,dp[n]=dp[n-1]+dp[n-2] dp[1]=2,dp[2]=3,dp[3]=5,dp[n]=dp[n1]+dp[n2]。(也可以直接推导得到该性质)

因此先通过斐波那契数列的常规求解方式求出 d p [ k ] dp[k] dp[k] d p [ k − 1 ] dp[k-1] dp[k1]。再求出 s u m [ x ] sum[x] sum[x] s u m [ x ] sum[x] sum[x] 表示长度小于等于 x x x,且长度是 K K K 倍数的 01 01 01 串总数。

假设 a a a 是最大的小于 L L L K K K 的倍数, b b b 是最大的小于 R R R 且大于 L L L K K K 的倍数,则 a n s = s u m [ b ] − s u m [ a ] ans=sum[b]-sum[a] ans=sum[b]sum[a]

( d p [ i − 1 ] d p [ i ] s u m [ i ] ) ∗ ( 0 1 1 1 1 1 0 0 1 ) = ( d p [ i ] d p [ i + 1 ] s u m [ i + 1 ] ) \begin{pmatrix} dp[i-1] & dp[i] & sum[i] \end{pmatrix}*\begin{pmatrix} 0 & 1 & 1\\ 1 & 1 & 1\\ 0 & 0 & 1\end{pmatrix}=\begin{pmatrix} dp[i] & dp[i+1] & sum[i+1] \end{pmatrix} (dp[i1]dp[i]sum[i])010110111=(dp[i]dp[i+1]sum[i+1])

但是 s u m [ x ] sum[x] sum[x] 只表示长度为 K K K 倍数的 01 01 01 串的总数,因此仅当 d p [ i ] dp[i] dp[i] i i i K K K 的倍数时, d p [ i ] dp[i] dp[i] 才会被累加到答案 s u m [ i ] sum[i] sum[i] 中。

( d p [ k − 1 ] d p [ k ] s u m [ k ] ) ∗ ( 0 1 0 1 1 0 0 0 1 ) k − 1 ∗ ( 0 1 1 1 1 1 0 0 1 ) = ( d p [ 2 ∗ k − 1 ] d p [ 2 ∗ k ] s u m [ 2 ∗ k ] ) \begin{pmatrix} dp[k-1] & dp[k] & sum[k] \end{pmatrix}*\begin{pmatrix} 0 & 1 & 0\\ 1 & 1 & 0\\ 0 & 0 & 1\end{pmatrix}^{k-1}*\begin{pmatrix} 0 & 1 & 1\\ 1 & 1 & 1\\ 0 & 0 & 1\end{pmatrix}=\begin{pmatrix} dp[2*k-1] & dp[2*k] & sum[2*k] \end{pmatrix} (dp[k1]dp[k]sum[k])010110001k1010110111=(dp[2k1]dp[2k]sum[2k])

此处 s u m [ 2 ∗ k ] = s u m [ k ] + d p [ 2 ∗ k ] sum[2*k]=sum[k]+dp[2*k] sum[2k]=sum[k]+dp[2k],因此先矩阵快速幂求出 k − 1 k-1 k1 阶的矩阵,乘上后面的 1 1 1 阶矩阵,得到矩阵 b a s e base base,再对 b a s e base base 进行快速幂,求出 s u m [ a ] sum[a] sum[a] s u m [ b ] sum[b] sum[b],即可得到答案。


总结:

此题的主要难点应该在于打表,如果不能发现 d p dp dp 数组是斐波那契数组的话,还是非常难以进行后续矩阵快速幂的推导的。

注意矩阵快速幂的矩阵乘积形式一定要写正确,比赛时将左边的横矩阵写成了列矩阵,导致一直 W a Wa Wa,很是痛心!


代码:

代码改来改去的,非常丑陋,不具有借鉴价值…

#include <cstdio>
#include <iostream>
#include <cstring>
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define LOG1(x1,x2) cout << x1 << ": " << x2 << endl;
#define LOG2(x1,x2,y1,y2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << endl;
#define LOG3(x1,x2,y1,y2,z1,z2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << " , " << z1 << ": " << z2 << endl;
typedef long long ll;
using namespace std; 
const int mod = 1e9+7;
typedef long long ll;
 
ll L,R,K;
//i、k、j只能作为临时变量 
struct Matrix{
	ll a[10][10];
	Matrix(){memset(a,0,sizeof(a));}
	
	Matrix operator * (const Matrix y)
	{
		Matrix ans;
		for(int i = 1;i <= 3;i++)   //行 
			for(int j = 1;j <= 3;j++)  //列 
				for(int k = 1;k <= 3;k++)
					ans.a[i][j] = (ans.a[i][j]+a[i][k]*y.a[k][j]%mod)%mod;			
		return ans;
	}
};
 
Matrix q_pow(Matrix x,ll k)
{
	Matrix ans = x; k--;
	while(k > 0)
	{
		if(k&1)
			ans = ans*x;
		x = x*x;
		k = k>>1;
	}
	return ans;
}
 
ll solve(ll a1,ll a2,ll sum1, Matrix x,ll n){ //求sum[k], n >= 2
	Matrix tp = q_pow(x,n-1ll);
	ll ans = ((tp.a[1][3]*a1%mod+tp.a[2][3]*a2%mod)%mod+tp.a[3][3]*sum1%mod)%mod;
	return ans;
}
 
int main()
{
	int _; scanf("%d",&_);
	rep(Ca,1,_)
	{
		scanf("%lld%lld%lld",&L,&R,&K);
		Matrix p;
		for(int i = 1;i <= 3;i++)
			for(int j = 1;j <= 3;j++)
				p.a[i][j] = 1;
		p.a[1][1] = p.a[3][1] = p.a[3][2] = 0;
		ll a1 = 2, a2 = 3, sum1 = 5;
		if(K >= 3){
			Matrix tmp = q_pow(p,K-2ll);
			a1 = ((tmp.a[1][1]*2ll%mod+tmp.a[2][1]*3ll%mod)%mod+tmp.a[3][1]*5ll%mod)%mod;
			a2 = ((tmp.a[1][2]*2ll%mod+tmp.a[2][2]*3ll%mod)%mod+tmp.a[3][2]*5ll%mod)%mod;
			sum1 = a2;
		}
		else if(K == 1){
			ll ans1 = 0, ans2 = 0;
			if(L == 1) ans1 = 0;
			else if(L == 2) ans1 = 2;
			else if(L == 3) ans1 = 5;
			else{
				Matrix tmp = q_pow(p,L-3);
				ans1 = ((tmp.a[1][3]*2ll%mod+tmp.a[2][3]*3ll%mod)%mod+tmp.a[3][3]*5ll%mod)%mod;
			}
 
			if(R == 1) ans2 = 2;
			else if(R == 2) ans2 = 5;
			else{
				Matrix tmp = q_pow(p,R-2);
				ans2 = ((tmp.a[1][3]*2ll%mod+tmp.a[2][3]*3ll%mod)%mod+tmp.a[3][3]*5ll%mod)%mod;
			}
			printf("Case %d: %lld\n",Ca,(ans2-ans1+mod)%mod);
			continue;
		}
		else sum1 = 3;
 
		Matrix tp1,tp2;
		for(int i = 1;i <= 3;i++)
			for(int j = 1;j <= 3;j++)
				tp1.a[i][j] = 1;
		tp1.a[1][1] = tp1.a[3][1] = tp1.a[3][2] = tp1.a[1][3] = tp1.a[2][3] = 0ll;
 
		for(int i = 1;i <= 3;i++)
			for(int j = 1;j <= 3;j++)
				tp2.a[i][j] = 1;
		tp2.a[1][1] = tp2.a[3][1] = tp2.a[3][2] = 0;
 
		Matrix base = q_pow(tp1,K-1ll)*tp2;	
		ll hp1,hp2;
		hp1 = (L/K)*K;
		if(hp1 == L) hp1 = (L/K-1ll)*K;
 
		hp2 = R/K;
		ll ans1 = 0ll,ans2 = 0ll;
		if(hp2 > 1ll){
			ans1 = solve(a1,a2,sum1,base,hp2);
		}
		else if(hp2 == 1) ans1 = sum1;
 
		if(hp1 > K) ans2 = solve(a1,a2,sum1,base,hp1/K);
		else if(hp1 == K) ans2 = sum1;
		// LOG2("ans1",ans1,"ans2",ans2);
		printf("Case %d: %lld\n",Ca,(ans1-ans2+mod)%mod);
	}
	return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Gene_INNOCENT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值