bzoj5082 弗拉格 矩阵乘法

123 篇文章 0 订阅
19 篇文章 0 订阅

Description


“如果明天进了面试,我就去爆妹子的照”——有妹子的丁相允作为一个oier,自然不能立太多flag,让我们来看
一道和flag有关的题目吧
给你n个flag,你要把每个染色成红黑白黄四色之一,满足:
1.相邻旗不能同色
2.白不能和黄相邻,红不能和黑相邻
3.不能存在连续三个球依次是“黑白红”或“红白黑”
4.翻转后相等视为等价
设不等价方案数为f(n),给定l,r,求
Sigmaf(i),其中L<=i<=R模1000000007
1<=L,R<=1000000000

Solution


关于struct的奇迹银翘get√
考虑状压,我们只需要记录后两位状态即可,合法状态仅有8种
很自然想到矩阵快速幂,关键在于第4个限制怎么处理
计不考虑限制4的答案为f[n],那么答案显然为(f[n]+回文答案)/2。注意到只有长度为奇数的回文串符合条件,且这些串一定能由两个长度为(n+1)/2的回文答案拼接,因此最终答案为(f[n]+f[(n+1)/2])/2

一开始写的时候没管限制3就gg了。。

Code


#include <stdio.h>
#include <string.h>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))

typedef long long LL;
const int MOD=1000000007;

struct Mat {
	LL r[10][10];

	Mat() {fill(r,0);}

	void ze() {
		fill(r,0);
		rep(i,1,9) r[i][i]=1;
	}

	LL* operator [](int x) {return r[x];}

	Mat operator *(Mat B) const {
		Mat A=*this,C;
		rep(i,1,9) rep(j,1,9) {
			rep(k,1,9) (C[i][j]+=A[i][k]*B[k][j]%MOD)%=MOD;
		}
		return C;
	}

	Mat operator ^(int dep) const {
		Mat A=*this,C; C.ze();
		for (;dep;dep>>=1) {
			if (dep&1) C=C*A;
			A=A*A;
		}
		return C;
	}
} A,B;

LL solve(int n) {
	if (!n) return 0;
	if (n==1) return 4;
	if (n==2) return 8;
	B=A^(n-1);
	LL ans=0;
	rep(i,1,8) ans=(ans+B[i][9])%MOD; ans+=4;
	if ((n+1)/2==0) ans+=0;
	else if ((n+1)/2==1) ans+=4;
	else if ((n+1)/2==2) ans+=12;
	else {
		B=A^((n+1)/2-1);
		rep(i,1,8) ans=(ans+B[i][9])%MOD; ans+=4;
	}
	ans=ans*500000004LL%MOD;
	return ans;
}

int main(void) {
	freopen("data.in","r",stdin);
	freopen("myp.out","w",stdout);
	A[5][1]=A[7][2]=A[8][2]=1;
	A[6][3]=A[7][4]=A[8][4]=1;
	A[1][5]=A[2][5]=A[3][6]=A[4][6]=1;
	A[1][7]=A[2][7]=A[3][8]=A[4][8]=1;
	rep(i,1,9) A[i][9]=1;
	int l,r; scanf("%d%d",&l,&r);
	LL ans=solve(r);
	ans-=solve(l-1);
	ans=(ans%MOD+MOD)%MOD;
	printf("%lld\n", ans);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值