POJ2865 Birthday toy[Polay+矩阵快速幂优化dp]

B i r t h d a y   t o y Birthday\ toy Birthday toy


D e s c r i p t i o n \mathcal{Description} Description
有一个 n n n个珠子的环,中心还有一颗珠子,用 k k k种颜色来染。要求相邻珠子的颜色不同,中心珠子的颜色不能和外围任意一颗珠子的颜色一样,考虑旋转,问本质不同的珠子个数?

做这道题之前推荐先看一下这道题


最 初 想 法 最初想法
中间的珠子颜色提前分配就好, 以 下 颜 色 数 量 M 均 经 过 减 一 操 作 . \color{red}{以下颜色数量 M 均经过减一操作.} M.
对于置换 " 旋 转 k 次 " "旋转k次" "k", 方案数量为 M ∗ ( M − 1 ) ∗ . . . ∗ ( M − 2 ) M*(M-1)*...*(M-2) M(M1)...(M2), 按这个方法计算就可以了 .

错因是到 i − 1 i-1 i1 时, 在前面计算出来的方案数中既包含 i − 2 i-2 i2 1 1 1 相同的方案数, 也包含不同的方案数,
于是当前 i − 1 i-1 i1 的选择并不是 M − 2 M-2 M2 种 .


正 解 部 分 正解部分
F [ i ] F[i] F[i] 表示 i i i 个元素成环时的方案数量,
假设已经知道了 F [ i − 1 ] , F [ i − 2 ] F[i-1],F[i-2] F[i1],F[i2], 考虑推出 F [ i ] F[i] F[i],

  1. 由于 F [ i − 1 ] F[i-1] F[i1]表示在 i − 1 i-1 i1 1 1 1 的颜色不同的前提下 i − 1 i-1 i1 的方案,
    此时的 i i i M − 2 M-2 M2 种选择,
    ∴   i − 1 \therefore\ i-1  i1 i i i 颜色不同时, F [ i ]   + = F [ i − 1 ] ∗ ( M − 2 ) F[i]\ += F[i-1]*(M-2) F[i] +=F[i1](M2)

  2. 那么 i − 1 i-1 i1 i i i 颜色相同的方案数量呢 ?

    由于 i − 1 i-1 i1 1 1 1 的颜色相同, F [ i − 2 ] F[i-2] F[i2] 又表示 i − 2 i-2 i2 1 1 1 颜色不同的方案数量, 间接也表示了 i − 2 i-2 i2 i − 1 i-1 i1 的颜色也不同, 将 i − 1 i-1 i1 插入 i − 2 i-2 i2 后面, 满足了邻位不同, 且 i i i i − 1 i-1 i1相同的条件,

    此时 i i i M − 1 M-1 M1 种选择
    ∴   i − 1 \therefore\ i-1  i1 i i i 颜色相同时, F [ i ]   + = F [ i − 2 ] ∗ ( M − 1 ) F[i]\ += F[i-2]*(M-1) F[i] +=F[i2](M1) .

∴   综 上 所 述     F [ i ] = ( M − 2 ) ∗ F [ i − 1 ] + ( M − 1 ) ∗ F [ i − 2 ] \therefore\ 综上所述\ \ \ F[i]=(M-2)*F[i-1]+(M-1)*F[i-2]     F[i]=(M2)F[i1]+(M1)F[i2]

有点像斐波那契数列是吧?
于是可以使用 矩阵快速幂 优化.

最后枚举约数, 用 P o l y a Polya Polya求解即可, 具体点击这里查看拓展2 .

时间复杂度 O ( N l o g N ) O(\sqrt{N}logN) O(N logN) .


实 现 部 分 实现部分
没什么好说的 , 给出代码供参考.

#include<cstdlib>
#include<cstdio>
#include<cstring>
#define reg register

const int mod = 1000000007;

int N;
int M;
int Tmp_2;
int Tmp_3;
//{{{
struct Matrix{
        int C[4][4];
        Matrix(){ memset(C, 0, sizeof C); }
} A, B, C;

Matrix Modify(Matrix a, Matrix b){
        Matrix s;
        for(reg int i = 1; i <= 2; i ++)
                for(reg int j = 1; j <= 2; j ++){ 
                        int &t = s.C[i][j];
                        for(reg int k = 1; k <= 2; k ++)
                                t = (t+(1ll*a.C[i][k]%mod)*(b.C[k][j]%mod)%mod) % mod;
                }
        return s;
}

Matrix KSM(Matrix a, int b){
        Matrix s;
        for(reg int i = 1; i <= 2; i ++) s.C[i][i] = 1;
        while(b){
                if(b & 1) s = Modify(s, a);
                a = Modify(a, a);
                b >>= 1;
        }
        return s;
}

int KSM_1(int a, int b){
        a %= mod;
        int s = 1;
        while(b){
                if(b & 1) s = 1ll*s*a % mod;
                a = 1ll*a*a % mod;
                b >>= 1;
        }
        return s;
}

int phi(int x){
        int s = x;
        for(reg int i = 2; i*i <= x; i ++){
                if(x % i) continue ;
                s = s/i*(i-1);
                while(x%i == 0) x /= i;
        }
        if(x > 1) s = s/x*(x-1);
        return s%mod;
}
//}}}
void Calc(int &Ans, int d){
        if(d == 2){
                Ans = ((1ll*phi(N/d)*Tmp_2)%mod + 1ll*Ans) % mod;
                return ;
        }
        else if(d == 3){
                Ans = ((1ll*phi(N/d)*Tmp_3)%mod + 1ll*Ans) % mod;
                return ;
        }
        B = KSM(A, d-3);
        int t = (1ll*B.C[1][1]*Tmp_3%mod + 1ll*B.C[2][1]*Tmp_2%mod) % mod;
        int tmp = (1ll*t*phi(N/d)) % mod;
        Ans = (1ll*Ans + tmp) % mod;
}

void Work(){
        M --;
        A.C[1][1] = M-2, A.C[1][2] = 1;
        A.C[2][1] = M-1, A.C[2][2] = 0;
        Tmp_2 = 1ll*(M%mod) * (M-1) % mod;
        Tmp_3 = 1ll*M%mod * (1ll*M-1)%mod;
        Tmp_3 = 1ll*Tmp_3 * (M-2) % mod;
        int Ans = 0;
        for(reg int d = 1; d*d <= N; d ++){
                if(N % d) continue ;
                if(d != 1) Calc(Ans, d);
                int d1 = N/d;
                if(d1 == d) continue ;
                Calc(Ans, d1);
        }
        int tmp = (M+1) % mod;
        Ans = 1ll*Ans*tmp % mod;
        Ans = 1ll*Ans*KSM_1(N, mod-2)%mod;
        printf("%d\n", Ans);
}

int main(){
        while(~scanf("%d%d", &N, &M)) Work();
        return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是Java解决POJ3233—矩阵幂序列问题的代码和解释: ```java import java.util.Scanner; public class Main { static int n, k, m; static int[][] A, E; public static void main(String[] args) { Scanner sc = new Scanner(System.in); n = sc.nextInt(); k = sc.nextInt(); m = sc.nextInt(); A = new int[n][n]; E = new int[n][n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { A[i][j] = sc.nextInt() % m; E[i][j] = (i == j) ? 1 : 0; } } int[][] res = matrixPow(A, k); int[][] ans = matrixAdd(res, E); printMatrix(ans); } // 矩阵乘法 public static int[][] matrixMul(int[][] a, int[][] b) { int[][] c = new int[n][n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { for (int k = 0; k < n; k++) { c[i][j] = (c[i][j] + a[i][k] * b[k][j]) % m; } } } return c; } // 矩阵快速幂 public static int[][] matrixPow(int[][] a, int b) { int[][] res = E; while (b > 0) { if ((b & 1) == 1) { res = matrixMul(res, a); } a = matrixMul(a, a); b >>= 1; } return res; } // 矩阵加法 public static int[][] matrixAdd(int[][] a, int[][] b) { int[][] c = new int[n][n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { c[i][j] = (a[i][j] + b[i][j]) % m; } } return c; } // 输出矩阵 public static void printMatrix(int[][] a) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { System.out.print(a[i][j] + " "); } System.out.println(); } } } ``` 解释: 1. 首先读入输入的n、k、m和矩阵A,同时初始化单位矩阵E。 2. 然后调用matrixPow函数求出A的k次幂矩阵res。 3. 最后将res和E相加得到结果ans,并输出。 4. matrixMul函数实现矩阵乘法,matrixPow函数实现矩阵快速幂,matrixAdd函数实现矩阵加法,printMatrix函数实现输出矩阵。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值