zoukankan      html  css  js  c++  java
  • Luogu P5303 [GXOI/GZOI2019]逼死强迫症

    怎么还有这么SB的省选题啊

    首先容易想到枚举右边的一个(1 imes 1)的小方块所在的列(i),然后暴枚左边小方块所在的列(j)在哪里,然后我们发现所有(jin [1,i-1))的列都有且仅有一种选择,具体和两者纵坐标的差值有关,画个图就知道了

    然后每一对(i,j)的贡献是多少呢,很简单,显然在([i,j])之间的列只有唯一的放置方案,那么要乘上的系数就是两边(2 imes (i-1))(2 imes (n-j))大小的放法了

    我们令(2 imes i)大小的放置方案为(f_i),考虑每次在右边放,要么是竖着从(f_{i-1})转移而来,要么是横着放两个从(f_{i-2})转移来,因此这就是一个斐波那契数列

    然后考虑前面那个暴力的思路,我们预处理出(f_i)(f_i)的前缀和(s_i)即可拿到50pts(注意右边的有上下两种方法互相等价,因此要( imes 2)

    50pts暴力代码

    #include<cstdio>
    #define RI register int
    using namespace std;
    const int N=1e5+5,mod=1e9+7;
    int t,n,ans,fib[N],sum[N];
    inline void init(void)
    {
    	sum[0]=fib[0]=fib[1]=1; for (RI i=sum[1]=2;i<N;++i)
    	fib[i]=(fib[i-2]+fib[i-1])%mod,sum[i]=(sum[i-1]+fib[i])%mod;
    }
    int main()
    {
    	for (scanf("%d",&t),init();t;--t)
    	{
    		RI i; for (scanf("%d",&n),ans=0,i=3;i<=n;++i)
    		(ans+=2LL*sum[i-3]*fib[n-i]%mod)%=mod; printf("%d
    ",ans);
    	}
    	return 0;
    }
    

    然后我们再用类似(f_i)的推导方式推导答案(F_i),考虑如何从之前的状态转移而来

    很容易用一样的思路得到,如果之前(i-1)列没有放(1 imes 1)的小方块,那么(F_i)可以从(F_{i-1})(F_{i-2})转移来

    如果放了呢,那么其实就是上面暴力的转移过程,因为我们此时在第(i)列的放法唯一,因此系数就是(1)

    所以综合一下就有(F_i=F_{i-2}+F_{i-1}+2 imes s_{i-3}),然后用斐波那契数列前缀和的性质(s_i=f_{i+2}-1)即可推出(F_i=F_{i-2}+F_{i-1}+2 imes f_{i-1}-2)

    直接矩阵快速幂维护转移的(5)个值(有一个是常数项),复杂度(O(T imes 5^3 imes log n))

    100pts矩乘CODE

    #include<cstdio>
    #include<cstring>
    #define RI register int
    #define CI const int&
    using namespace std;
    const int N=5,mod=1e9+7;
    struct Matrix
    {
        int n,m; long long mat[N][N];
        inline Matrix(CI N=0,CI M=0) { n=N; m=M; memset(mat,0,sizeof(mat)); }
        inline long long* operator [] (CI x) { return mat[x]; }
        friend inline Matrix operator * (Matrix A,Matrix B)
        {
            Matrix C(A.n,B.m); for (RI i=0;i<C.n;++i)
            for (RI j=0;j<C.m;++j) for (RI k=0;k<A.m;++k)
            (C[i][j]+=A[i][k]*B[k][j])%=mod; return C;
        }
        friend inline Matrix operator ^ (Matrix A,long long p)
        {
            Matrix T(A.n,A.m); for (RI i=0;i<A.n;++i) T[i][i]=1;
            for (;p;p>>=1LL,A=A*A) if (p&1) T=T*A; return T;
        }
    }; int t,n;
    int main()
    {
        for (scanf("%d",&t);t;--t)
        {
            scanf("%d",&n); if (n<=2) { puts("0"); continue; }
            Matrix S(5,1),D(5,5); S[2][0]=S[3][0]=1; S[4][0]=2;
            D[0][0]=D[0][1]=D[1][0]=D[2][2]=D[2][3]=D[3][2]=D[4][4]=1;
            D[0][2]=2; D[0][4]=mod-1; S=(D^(n-1))*S; printf("%d
    ",S[0][0]);
        }
        return 0;
    }
    
  • 相关阅读:
    委托demo
    事件demo
    数据结构与算法分析表ADT
    数据结构与算法分析栈ADT
    Access的“自动编号”问题
    C#获取时间函数
    在load事件中关闭窗体
    panel里面显示form的问题
    将RichTextBox 的内容直接写入数据库
    利用反射来创建一个Form.
  • 原文地址:https://www.cnblogs.com/cjjsb/p/10961051.html
Copyright © 2011-2022 走看看