「P5004」专心OI - 跳房子 解题报告
Posted hovny
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「P5004」专心OI - 跳房子 解题报告相关的知识,希望对你有一定的参考价值。
题面
把(N)个无色格子排成一行,选若干个格子染成黑色,要求每个黑色格子之间至少间隔(M)个格子,求方案数
思路:
矩阵加速
根据题面,这一题似乎可以用递推
设第(i)个格子的编号为(i),有(i)个格子时的方案数为(f(i))
显然,当 (i le M+1) 时,
可以所有格子不染色(方案数为(1)种,或者最多有一个格子染色(方案数为(i)种)
所以有(f(i)=i+1)
当(i>M+1)时,
对于第(i)个格子可以由第(i-1)个格子转移过来,
而第(i)个格子有两种情况
1、不染色,显然可以这种情况下方案数为(f(i-1))
2、染色,可以看出第([i-m,i-1])个格子必定不染色,也就是没有贡献的,方案数为(f(i-m-1))
但是!
(N le 10^{18}),(M le 15)
可以使用矩阵加速递推
求解
我们要记录的是应该是(f(i) o f(i+m))一共(m+1)个元素,于是就用一个((M+1)^2)的矩阵进行加速,配合快速幂求解
Code:
#include<bits/stdc++.h>
#define ll long long
#define Mod 1000000007
#define N 20
using namespace std;
int n;
ll b;
struct node{//矩阵放结构体里
ll f[N][N];
}res,a;
node operator* (const node a,const node b)//重载*运算
{
int i,j,k;
node c;ll res;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
res=0;
for(k=0;k<n;k++)
res=(res+a.f[i][k]*b.f[k][j])%Mod;
c.f[i][j]=res;
}
return c;
}
void init(){//初始化
int i;
for(i=0;i<n;i++) res.f[0][i]=i+2;//矩阵下标从0开始,所以+2
for(i=0;i<n-1;i++) a.f[i+1][i]=1;
a.f[n-1][n-1]=a.f[0][n-1]=1;
}
void quickPow(ll b)
{
while(b)
{
if(b&1) res=res*a;
b>>=1;a=a*a;
}
}
int main()
{
scanf("%lld%d",&b,&n);--b,++n;//res初始为b=1的情况,所以实际的b要-1
init();quickPow(b);//n++是方便计算间隔
printf("%lld",res.f[0][0]);
return 0;
}
以上是关于「P5004」专心OI - 跳房子 解题报告的主要内容,如果未能解决你的问题,请参考以下文章
解题报告多项式求值与插值(拉格朗日插值)(ACM / OI)
Moscow Pre-Finals Workshop 2016. Japanese School OI Team Selection. 套题详细解题报告