ACM-ICPC 2018 焦作赛区网络预赛 - L. Poor God Water (矩阵快速幂)

版权声明:是自己手打的没错 https://blog.csdn.net/Mr_Treeeee/article/details/82728953

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

猜你喜欢

转载自blog.csdn.net/Mr_Treeeee/article/details/82728953