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;
}