• 【JZOJ4248】n染色【矩阵乘法】


    题目大意:

    题目链接:https://jzoj.net/senior/#main/show/4248
    求一个nn条边的多边形,相邻两边选择不同的颜色,共mm种颜色的涂色方案数。


    思路:

    以下解题思路时我在考试时一步一步的推理,希望直接了解方法的可以跳到“总结”处。

    n1018nleq 10^{18}说明复杂度一定是loglog级别的。(O(1)O(1)的拜拜)
    先打一个表

    mm nn 3 4 5 6 7 8
    3 6 18 30 66 126 258
    4 24 84 240 732 2184 6564
    5 60 260 1020 4100 16380 65540
    6 120 630 3120 15630 78120 390630
    7 210 1302 7770 46662 279930 1679622
    8 336 2408 16800 117656 823536 5764808

    m=3m=3
    6,18,30,66,126,2586,18,30,66,126,258
    显然发现它们都有公因数6,于是全部除以6
    1,3,5,11,21,431,3,5,11,21,43
    很容易发现如下规律
    {ai=ai1×21(iodd)ai=ai1×2+1(ieven)left{egin{matrix}a_i=a_{i-1} imes 2-1(iin odd)\ a_i=a_{i-1} imes 2+1(iin even)end{matrix} ight.
    再来看m=4m=4
    24,84,240,732,2184,656424,84,240,732,2184,6564
    明显都有6的公因数,提出来
    4,14,40,122,364,10944,14,40,122,364,1094
    还有一个因数2诶!
    2,7,20,61,182,5472,7,20,61,182,547
    规律还是一样的!
    {ai=ai1×31(iodd)ai=ai1×3+1(ieven)left{egin{matrix}a_i=a_{i-1} imes 3-1(iin odd)\ a_i=a_{i-1} imes 3+1(iin even)end{matrix} ight.
    第一次gcdgcd是6,第二次是12。
    然后我就想到了小学奥数的列项。。。
    然后一试,发现m=5m=5的最大公约数确实是20。
    那么规律就出来了。


    总结

    {ai=ai1×(m1)1(iodd)ai=ai1×(m1)+1(ieven)left{egin{matrix}a_i=a_{i-1} imes (m-1)-1(iin odd)\ a_i=a_{i-1} imes (m-1)+1(iin even)end{matrix} ight.
    然后a1=m2a_1=m-2
    所以很明显就是一个矩阵乘法。
    在这里插入图片描述
    n3n-3遍矩阵乘法就可以了。


    代码:

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    
    const ll MOD=1e9+7;
    ll f[3][3],a[3][3],n,m;
    
    void mul(ll f[3][3],ll a[3][3])
    {
    	ll c[3][3]={{0,0,0},{0,0,0},{0,0,0}};
    	for (ll i=1;i<3;i++)
    		for (ll j=1;j<3;j++)
    			for (ll k=1;k<3;k++)
    				c[i][j]=(c[i][j]+f[i][k]*a[k][j]);
    	for (ll i=1;i<3;i++)
    		for (ll j=1;j<3;j++)
    			f[i][j]=c[i][j]%MOD;
    }
    
    void mulself(ll a[3][3])
    {
    	ll c[3][3]={{0,0,0},{0,0,0},{0,0,0}};
    	for (ll i=1;i<3;i++)
    		for (ll j=1;j<3;j++)
    			for (ll k=1;k<3;k++)
    				c[i][j]=(c[i][j]+a[i][k]*a[k][j]);
    	for (ll i=1;i<3;i++)
    		for (ll j=1;j<3;j++)
    			a[i][j]=c[i][j]%MOD;
    }
    
    int main()
    {
    	cin>>m>>n;
    	m-=3;
    	a[1][1]=(n-1)%MOD; a[2][1]=1; a[2][2]=-1;
    	f[1][1]=(n-2)%MOD; f[1][2]=1;
    	while (m>0)
    	{
    		if (m&1) mul(f,a);
    		mulself(a);
    		m>>=1;
    	}
    	cout<<f[1][1]%MOD*((n-1)%MOD)%MOD*(n%MOD)%MOD;
    	return 0;
    }
    
  • 相关阅读:
    缓冲区设置JAVA NIO 缓冲区
    互联网腾讯马化腾:微信拿到只是“站票” 我还会有紧迫感
    能力江湖做生意的能力
    指针对象C++ primer智能指针(HasPtr)实现
    脚本测试tsung
    字符搜索正则表达式语法详解
    【转载】表变量与临时表,变量表都以@或@@为前缀;临时表都以#或##为前缀
    ws2008
    【转载】Coolite之TreePanel右键功能菜单
    [转载]WCF技术剖析之三:如何进行基于非HTTP的IIS服务寄宿
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998332.html
Copyright © 2020-2023  润新知