• 【bzoj5082】弗拉格 矩阵乘法


    题目描述

    给你n个flag,你要把每个染色成红黑白黄四色之一,满足:
    1.相邻旗不能同色
    2.白不能和黄相邻,红不能和黑相邻
    3.不能存在连续三个球依次是“黑白红”或“红白黑”
    4.翻转后相等视为等价
    设不等价方案数为f(n),给定l,r,求
    Sigma f(i),其中L<=i<=R模1000000007

    输入

    输入两个数l,r
    l, r ≤ 10^9

    输出

    输出答案

    样例输入

    3 4

    样例输出

    23


    题解

    矩阵乘法

    容易设出dp状态 $f[i][j][k]$ 表示前 $i$ 个flag,最后一个的颜色为 $j$ ,倒数第二个的颜色为 $k$ 的方案数。

    显然这个dp方程可以使用矩阵乘法来加速转移,并使用计数器维护前缀和。

    至于翻转后相等视为等价的问题,易知:答案=(总方案数+翻转后与原来相等的方案数)/2。于是求出反转后与原来相等的方案数即可。

    容易发现偶数长度的中间两个一定相同,因此不存在偶数长度的回文串。

    对于奇数长度,发现题目条件的限制是对称的(AB<=>BA,ABC<=>CBA),因此某长度为 $2k-1$ 的奇数长度回文串的个数即为长度为 $k$ 的串的个数。再次求 $lceilfrac n2 ceil$ 的答案即可。

    最后前缀相减即为最终答案。

    时间复杂度 $O(9^3log n)$

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define mod 1000000007
    using namespace std;
    typedef long long ll;
    struct data
    {
    	ll v[9][9];
    	data() {memset(v , 0 , sizeof(v));}
    	ll *operator[](int a) {return v[a];}
    	data operator*(data &a)
    	{
    		data ans;
    		int i , j , k;
    		for(i = 0 ; i <= 8 ; i ++ )
    			for(j = 0 ; j <= 8 ; j ++ )
    				for(k = 0 ; k <= 8 ; k ++ )
    					ans[i][j] = (ans[i][j] + v[i][k] * a[k][j]) % mod;
    		return ans;
    	}
    }A;
    data pow(data x , int y)
    {
    	data ans;
    	int i;
    	for(i = 0 ; i <= 8 ; i ++ ) ans[i][i] = 1;
    	while(y)
    	{
    		if(y & 1) ans = ans * x;
    		x = x * x , y >>= 1;
    	}
    	return ans;
    }
    void init()
    {
    	int i;
    	for(i = 0 ; i <= 8 ; i ++ ) A[i][0] = 1;
    	A[1][5] = A[1][7] = 1;
    	A[2][5] = A[2][7] = 1;
    	A[3][6] = A[3][8] = 1;
    	A[4][6] = A[4][8] = 1;
    	A[5][1] = A[5][3] = 1;
    	A[6][1] = A[6][3] = 1;
    	A[7][2] = 1;
    	A[8][4] = 1;
    }
    ll calc(int x)
    {
    	if(!x) return 0;
    	data T = pow(A , x - 1);
    	ll ans = T[0][0] * 4;
    	int i;
    	for(i = 1 ; i <= 8 ; i ++ ) ans += T[i][0];
    	return ans % mod;
    }
    int main()
    {
    	int l , r;
    	scanf("%d%d" , &l , &r) , l -- ;
    	init();
    	printf("%lld
    " , ((calc(r) + calc((r + 1) / 2) - calc(l) - calc((l + 1) / 2)) * 500000004 % mod + mod) % mod);
    	return 0;
    }
    
  • 相关阅读:
    环境部署(八):jenkins配置邮件通知
    环境部署(七):linux下Jenkins+Git+JDK持续集成
    环境部署(六):Git关联github
    Git基础使用教程
    环境部署(五):Linux下安装Gradle
    环境部署(四):Linux下查看JDK安装路径
    从百小度看人工智能
    手游开发Android平台周边工具介绍
    移动开发工具推荐
    关于方法论的闲扯
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7886580.html
Copyright © 2020-2023  润新知