zoukankan      html  css  js  c++  java
  • 经典问题——选择颜色

    题目传送门

    选择颜色

    题目大意:

    n个人排成一个环形,每个人要从c种颜色中选择一个。
    牛牛希望相邻的人选择的颜色是不同的
    问有多少种方案。

    solution

    首先我们考虑当插入第n个颜色时,它所处的情况

    1. 第一种情况
      第n-1和第1个颜色相同,那么就有c-1种方案
    2. 第二种情况
      第n-1和第1个颜色不同,那么就有c-2种方案

    然后我们考虑递推

    设f[i]表示表示第i个和第1个相同的方案数,g[i]表示第i个和第1个不同的方案数。

    那么则有公式

    [egin{cases} f[i] = g[i - 1] imes c \ g[i] = f[i - 1] imes (c - 1) + g[i - 1] imes (c - 2)\ end{cases} ]

    边界条件是:f[1]=c,g[1]=0。这个根据定义就可以看出来
    然后就可以(O(n))爆推。

    可是这种方法还不足以过掉这道题。所以我们可以考虑矩阵快速幂。

    [egin{bmatrix} 0 & c \ c-1 & c-2 \ end{bmatrix} egin{bmatrix} f_i \ g_i\ end{bmatrix} = egin{bmatrix} f_{i+1} \ g_{i+1}\ end{bmatrix} ]

    矩阵公式就是如上。然后做n-1次快速幂就可以A掉这道题了

    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    const int mod = 10007;
    struct edge
    {
    	int a[5][5];
    };
    int n,c;
    edge muil(edge A,edge B){
    	edge C;
    	memset(C.a,0,sizeof(C.a));
    	for(int k=1;k<=2;k++)
    		for(int i=1;i<=2;i++)
    			for(int j=1;j<=2;j++)
    				C.a[i][j]+=((A.a[i][k]%mod)*(B.a[k][j]%mod))%mod,C.a[i][j]%=mod;
    	return C;
    }
    edge ksm(edge A,int y){
    	edge C;
    	memset(C.a,0,sizeof(C.a));
    	for(int i=1;i<=2;i++)C.a[i][i]=1;
    	while(y){
    		if(y&1)C=muil(C,A);
    		y>>=1;
    		A=muil(A,A);
    	}
    	return C;
    }	
    edge A;
    int D[3][3],E[3][3];
    int main(){
    	scanf("%d%d",&n,&c);
    	memset(A.a,0,sizeof(A.a));
    	A.a[2][2]=c-2;
    	A.a[2][1]=c-1;
    	A.a[1][2]=1;
    	A=ksm(A,n-1);
    	printf("%d",A.a[2][1] * c % mod);
            return 0;
    }
    
  • 相关阅读:
    【树】树的前序遍历(非递归)
    表单提交中的input、button、submit的区别
    利用setTimeout来实现setInterval
    Jquery动画操作的stop()函数
    Javascript实现简单的双向绑定
    Javascript观察者模式
    CSS reset
    【CSS3】background-origin和background-clip的区别
    :before和::before的区别
    JS实现瀑布流
  • 原文地址:https://www.cnblogs.com/ifmyt/p/9660287.html
Copyright © 2011-2022 走看看