zoj3690Choosing number 矩阵dp

28 篇文章 0 订阅
2 篇文章 0 订阅

zoj3690


(Small)S[ i ]  前i个数字排列的方案数  (最后一位小于等于K)

(Big)     B[ i ]  前i个数字排列的方案数   (最后一个数字大于K)


递推公式 :

S[ i ] = S[ i-1 ]*(K-1) + B[ i-1 ]*K

B[ i ] = S[ i-1 ]*(M-K) + B[ i-1 ]*(M-K)


最终总方案数为S[N]+B[N]

可惜由于N的范围太广 ,直接滚动求解超时


所以可以用矩阵来加速                                                           (   矩阵dp资料   例题    )

 

注意下面的乘法


K-1		K				S[i-1]				S[i]
				x					=
M-K		M-K				B[i-1]				B[i]


N次这样的矩阵相乘可以用快速幂来实现,log2(n)。。。


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

#define MOD 1000000007

int N,M,K;

struct Mat{
	unsigned long long m11,m12,m21,m22;
};

Mat Mul(Mat a,Mat b){			//2x2矩阵乘法 
	Mat ret={
				(a.m11*b.m11%MOD+a.m12*b.m21%MOD)%MOD,	(a.m11*b.m12%MOD+a.m12*b.m22%MOD)%MOD,
				(a.m21*b.m11%MOD+a.m22*b.m21%MOD)%MOD,	(a.m21*b.m12%MOD+a.m22*b.m22%MOD)%MOD
	};
	return ret;
}

int main()
{
	int i,j,k;
	while(scanf("%d%d%d",&N,&M,&K)!=EOF)
	{
		Mat o={1,0,0,1};				//单位矩阵
		Mat t={						//矩阵基本单元 
				K-1,	K,
				M-K,	M-K
		};
		N--;
		while(N>0)
		{
			if(N&1)
				o=Mul(o,t);
			N>>=1;
			t=Mul(t,t);
		}
		printf("%llu\n",(o.m11*K%MOD+o.m12*(M-K)%MOD+o.m21*K%MOD+o.m22*(M-K)%MOD)%MOD);
	}
	return 0;
}


ZOJ好像用不了 __int64


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值