https://nanti.jisuanke.com/t/31721
题意:
给你,肉、鱼、巧克力,让你找到有几种长度为n的排列。每3个长度满足条件。
当3种食物连续出现,巧克力不能在中间。
一种食物不能连续出现3次。
两边都是巧克力也不行。(针对长度为3的子串)
POINT:
把巧克力=0,其他为1,2。
可知长度为2的答案有9种。00,01,02,……,22
那么长度为3的怎么算。我们保存串的最后两个食物。
这样长度为2的这9种答案分别加上0,1,2,推到长度为3的答案。
比如00=10+20(即最后两位都是0的答案可以由10+0 20+0得到,00+0不符合题意)
比如01=00+10 (00+1,10+1)。
02=00+20。这样得到9个递推式。用矩阵快速幂加快速度即可。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define LL long long
const LL mod = 1e9+7;
struct node
{
LL a[9][9];
void init(){
memset(a,0,sizeof a);
}
node friend operator * (node a,node b)
{
node c;
c.init();
for(int k=0;k<9;k++)
for(int i=0;i<9;i++)
for(int j=0;j<9;j++){
c.a[i][j]+=a.a[i][k]*b.a[k][j]%mod;
c.a[i][j]%=mod;
}
return c;
}
};
node qkm(node base,LL mi)
{
node ans;
for(int i=0;i<9;i++)
for(int j=0;j<9;j++)
ans.a[i][j]=(i==j);
while(mi){
if(mi&1) ans=ans*base;
base=base*base;
mi>>=1;
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
LL n;
scanf("%lld",&n);
int base[9][9]={
0,1,1,0,0,0,0,0,0,
0,0,0,0,1,1,0,0,0,
0,0,0,0,0,0,0,1,1,
1,1,0,0,0,0,0,0,0,
0,0,0,1,0,1,0,0,0,
0,0,0,0,0,0,1,1,1,
1,0,1,0,0,0,0,0,0,
0,0,0,1,1,1,0,0,0,
0,0,0,0,0,0,1,1,0,
};
if(n==1)
{
printf("3\n");
continue;
}
node a;
for(int i=0;i<9;i++){
for(int j=0;j<9;j++)
a.a[i][j]=base[i][j];
}
a=qkm(a,n-2);
LL ans=0;
for(int i=0;i<9;i++)
for(int j=0;j<9;j++)
ans=(ans+a.a[i][j])%mod;
printf("%lld\n",ans);
}
return 0;
}
还有一种,也是二进制优化,在赛中胡乱搞得。
dp[x][y][z][xx][yy]代表长度为1<<z这个串 开头两个为xy,结尾两个为xx,yy的个数。
这样可以得到2进制整数的各个串的答案。
然后把n这个数用这些二进制的串 接起来就行了。写起来比较麻烦。
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;
#define LL long long
const LL N = 1e5 + 10;
const LL mod = 1e9+7;
LL dp[3][3][40][3][3];
void add(LL x,LL a,LL b,LL c,LL d)
{
for(LL j=0; j<3; j++)
{
for(LL k=0; k<3; k++)
{
for(LL jj=0; jj<3; jj++)
{
for(LL kk=0; kk<3; kk++)
{
dp[j][k][x][jj][kk]+=dp[j][k][x-1][a][b]*dp[c][d][x-1][jj][kk]%mod;
dp[j][k][x][jj][kk]%=mod;
}
}
}
}
}
LL f(LL x)
{
if(x==0||x==111||x==222||x==21||x==120||x==202||x==212)
return 0;
return 1;
}
LL check(LL a,LL b,LL c,LL d)
{
LL s1=a*100+b*10+c;
LL s2=b*100+c*10+d;
if(f(s1)&&f(s2))
return 1;
return 0;
}
LL p=0;
void init()
{
memset(dp,0,sizeof dp);
for(LL i=0; i<3; i++)
for(LL j=0; j<3; j++)
dp[i][j][1][i][j]=1;
for(LL i=2; (1LL<<i)<=1e10; i++)
{
LL p=0;
for(LL j=0; j<3; j++)
{
for(LL k=0; k<3; k++)
{
for(LL jj=0; jj<3; jj++)
{
for(LL kk=0; kk<3; kk++)
if(check(j,k,jj,kk))
{
p++;
add(i,j,k,jj,kk);
}
}
}
}
}
}
LL ans[3][3];
LL to=0;
void ff(LL x)
{
for(LL j=0; j<3; j++)
for(LL k=0; k<3; k++)
for(LL jj=0; jj<3; jj++)
for(LL kk=0; kk<3; kk++)
ans[jj][kk]+=dp[j][k][x][jj][kk],ans[jj][kk]%=mod;
}
void fff(LL x)
{
LL temp[3][3];
memset(temp,0,sizeof temp);
for(LL j=0; j<3; j++)
for(LL k=0; k<3; k++)
for(LL jj=0; jj<3; jj++)
for(LL kk=0; kk<3; kk++)
{
if(check(j,k,jj,kk)){
for(LL a=0;a<3;a++){
for(LL b=0;b<3;b++){
temp[a][b]+=ans[j][k]*dp[jj][kk][x][a][b]%mod;
temp[a][b]%=mod;
}
}
}
}
for(LL i=0;i<3;i++)
for(LL j=0;j<3;j++){
ans[i][j]=temp[i][j];
}
}
int main()
{
init();
LL T;
scanf("%lld",&T);
while(T--){
LL n;
scanf("%lld",&n);
memset(ans,0,sizeof ans);
if(n==1){
printf("3\n");
continue;
}
LL i;
for(i=40;i>=1;i--){
if((1LL<<i)&n){
ff(i);
break;
}
}
i--;
for(;i>=0;i--){
if((1LL<<i)&n){
if(i==0){
}else{
fff(i);
}
}
}
LL sum=0;
if(n&1){
for(LL i=0;i<3;i++){
for(LL j=0;j<3;j++){
for(LL k=0;k<3;k++){
LL a=j*100+k*10+i;
if(f(a)){
sum+=ans[j][k];
sum%=mod;
}
}
}
}
}else{
for(LL j=0;j<3;j++)
for(LL k=0;k<3;k++)
sum+=ans[j][k],sum%=mod;
}
cout<<sum<<endl;
}
return 0;
}