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;
    }
    
  • 相关阅读:
    jq ajax注册检查用户名
    jq ajax页面交互
    Digit Counting UVA – 1225
    Molar mass UVA – 1586
    P1571 眼红的Medusa
    A. Digits Sequence Dividing
    Codeforces Round #535 (Div. 3) a题
    Digit Generator UVA – 1583
    Good Bye 2018 B
    电梯 HDU – 1008
  • 原文地址:https://www.cnblogs.com/hovny/p/10415275.html
Copyright © 2011-2022 走看看