POJ 3734

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40924940/article/details/83662645

题意

有 n 个板子 四种颜色(红绿蓝黄),对 n 个板子涂色,在确保 红绿色板子 均为偶数个的情况下 有多少种涂色方案(对10007取模)

n<1e9

首先 暴力搜索就不用去想了,这道题要是做的话需要 dp 也就是递推的方法 我们试想一下 对于当前 n 块板子一共有几种情况?

An   : 红绿都达到偶数个了

Bn   : 只有红或绿达到偶数个了

Cn   : 都没有达到偶数个

既然DP的思想是由一种已知情况推测出未知情况, 那么 对 An+1 Bn+1 Cn+1 我们都可以用已知的信息推测出。

Ai+1 =  2 * Ai (接下来一块不涂红绿 涂蓝或黄 两种情况) + Bi (那种颜色不满足 涂哪种颜色)

Bi+1 =  2 * Ai(随意涂一个红或绿) + 2 * Bi(随意涂一个蓝或黄) + 2 * Ci(涂红或绿)

Ci+1 =  Bi(把凑够偶数个那个颜色涂掉) + 2 * Ci(涂蓝或黄)

这样就凑出了三个递推式

我们似乎发现了一些规律  回想一下之前见到的那个斐波那契数列题,这道题也可以利用矩阵的性质来快速完成掉

纵向还是 [Ai Bi Ci]  而我们需要一个 3*3矩阵, 那么看一下递推式 我们不难推出这个矩阵

          [    2    1    0    ]

X  =   [     2    2    2   ]         然后运用快速幂 就可以快速求解 得出的结果 我们就记录在了 第一列 而 第一列第一行 是 Ai 

          [     0    1    2    ]

AC代码如下:(这次我尝试了重载运算符)

    #include<iostream>
    #include<cstring>
    using namespace std;
    const int mod = 1e4+7;
    struct matrix
    {
        int m[3][3];
        matrix friend operator * (matrix a,matrix b)
	    {
		matrix tp;
		memset(tp.m,0,sizeof(tp.m));
		for(int i=0;i<3;++i)
		{
			for(int j=0;j<3;++j)
			{
				if(!a.m[i][j])
				{
					continue;
				}
				for(int k=0;k<3;++k)
				{
					tp.m[i][k]+=(a.m[i][j]*b.m[j][k])%mod;
					tp.m[i][k]%=mod;
				}
			}
		}
		return tp;
	    }
    };
    matrix base;
    int pow(matrix x,int n)
    {
        matrix ans={0};
	    for(int i=0;i<3;++i)
	    {
	 	    ans.m[i][i]=1;
	    }
        while(n)
        {
            if(n&1)
                ans = ans * x;
            x = x * x;
            n>>=1;
        }
        return ans.m[0][0];
    }
    int n;
    int main()
    {
        int test;
        cin>>test;
        while(test--)
        {
            cin>>n;
            matrix base={2,1,0,2,2,2,0,1,2};
            cout<<pow(base,n)<<endl;
        }
        return 0;
    }

猜你喜欢

转载自blog.csdn.net/qq_40924940/article/details/83662645
POJ