ccfcsp认证--2020年6月场1246

题目

原题链接

解题思路:不考虑最后一种|S|>2的情况

动态规划

下一秒的字符串依赖于上一秒的字符串。以|S|=1为例,依赖关系如下表所示

上一秒的数字下一秒的数字
12
24
41和6
66和4

知道上一秒1246四个数字的个数,便可推的下一秒四个数字各自的个数。
考虑|S|=2的情况,考虑到11、12等字符不会出现在最终的结果中,最终的结果中只会出现1、2、4、6、16、26、41、42、44、46、61、62、64、66这14种情况,除此之外便可直接输出0。
上一秒出现的4、41、42、44、46、64等情况均会导致下秒出现16,但他们均是因为含有4才会出现16,为避免重复,下一秒16的个数仅依赖与上秒中4的个数。类似的情况还有下一秒64的个数仅依赖于上秒中6和42的个数。
从而得到|S|<=2时的依赖情况如下表所示

124616264142444661626466
101000000000000
200100000000000
410011000000000
600110000000010
1600000100000000
2600000000010000
4100000000000100
4200000000000010
4400000000001000
4600000000000001
6100000001000000
6200000000100000
6400000010010000
6600000000000000

表中最左边一列代表上秒的数字,最上面一行代表下一秒的数字,为1时存在依赖关系,为0时不存在依赖关系。

算法加速满足时间要求

参考斐波那契数列数列的求法,构造dp矩阵如下:

long long int dp[14][14]={
		{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
		{0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}
	};

初始时2的个数为1,构造初始矩阵如下:

long long int begin_matrix[14]={0,1,0,0,0,0,0,0,0,0,0,0,0,0};

最终的结果:result=begin_matrix*dp^(n-1)
采用分治算法求解矩阵的n次方,参考我的博客幂乘算法

代码

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
#define RAW 14
#define COL 14//定义数组大小
using namespace std;
long long int begin_matrix[14]={0,1,0,0,0,0,0,0,0,0,0,0,0,0};
long long int result[14]=      {0,0,0,0,0,0,0,0,0,0,0,0,0,0};
long long int dp_n[14][14];
void  mul_matrix(long long  a[RAW][COL],long long  b[RAW][COL],long long  c[RAW][COL]){

    for(int i=0;i<RAW;++i){
        for(int k=0;k<COL;++k){
            c[i][k]=0;
            for(int j=0;j<COL;++j){
                 c[i][k]+=a[i][j]*b[j][k];
                 if(c[i][k]>=998244353) c[i][k]=c[i][k]%998244353;
            }
        }
    }
}
void final_result(){
        for(int k=0;k<14;++k){
            for(int j=0;j<14;++j){
                result[k]+=begin_matrix[j]*dp_n[j][k];
            }
        }


}
void copy_matrix(long long a[][COL],long long b[][COL]){
    for(int i=0;i<RAW;++i)
        for(int j=0;j<COL;++j)
            b[i][j]=a[i][j];
}
void matrix_n(long long a[][COL],long long c[][COL],long long int n){
    if(n==2){
        mul_matrix(a,a,c);
        return;
    }
    if(n==1){
        copy_matrix(a,c);
        return;
    }
    if(n%2==0){
        matrix_n(a,c,n/2);
        long long copy_c[RAW][COL];
        copy_matrix(c,copy_c);
        mul_matrix(copy_c,copy_c,c);
        return ;
    }
    else{
        matrix_n(a,c,(n-1)/2);
        long long copy_c[RAW][COL];
        copy_matrix(c,copy_c);
        mul_matrix(copy_c,copy_c,c);
        copy_matrix(c,copy_c);
        mul_matrix(copy_c,a,c);
    }
}
int main(){
    long long int dp[14][14]={
		{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
		{0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}
	};
	long long int n;
	cin>>n;
	if(n>1){
        matrix_n(dp,dp_n,n-1);
        final_result();
	}
	else{
        result[1]=1;
	}
	int output;
	cin>>output;
	switch(output){
    case 1:
        cout<<result[0];
        break;
    case 2:
        cout<<result[1];
        break;
    case 4:
        cout<<result[2];
        break;
    case 6:
        cout<<result[3];
        break;
    case 16:
        cout<<result[4];
        break;
    case 26:
        cout<<result[5];
        break;
    case 41:
        cout<<result[6];
        break;
    case 42:
        cout<<result[7];
        break;
    case 44:
        cout<<result[8];
        break;
    case 46:
        cout<<result[9];
        break;
    case 61:
        cout<<result[10];
        break;
    case 62:
        cout<<result[11];
        break;
    case 64:
        cout<<result[12];
        break;
    case 66:
        cout<<result[13];
        break;
    default:
        cout<<0;
        break;
        }
    return 0;
}

得分

不考虑最后一种情况,理应得到96分,但提交后只有92分,实在找不出问题在哪,欢迎大家在评论区指出我的错误

参考资料

博客网址
ccfcsp官方视频讲解

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值