zoukankan      html  css  js  c++  java
  • 「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;
    }
    
  • 相关阅读:
    118/119. Pascal's Triangle/II
    160. Intersection of Two Linked Lists
    168. Excel Sheet Column Title
    167. Two Sum II
    172. Factorial Trailing Zeroes
    169. Majority Element
    189. Rotate Array
    202. Happy Number
    204. Count Primes
    MVC之Model元数据
  • 原文地址:https://www.cnblogs.com/hovny/p/10415275.html
Copyright © 2011-2022 走看看