CCF CSP 有趣的数 动态规划

    xiaoxiao2021-03-25  66

    问题描述   我们把一个数称为有趣的,当且仅当:   1. 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次。   2. 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前。   3. 最高位数字不为0。   因此,符合我们定义的最小的有趣的数是2013。除此以外,4位的有趣的数还有两个:2031和2301。   请计算恰好有n位的有趣的数的个数。由于答案可能非常大,只需要输出答案除以1000000007的余数。 输入格式   输入只有一行,包括恰好一个正整数n (4 ≤ n ≤ 1000)。 输出格式   输出只有一行,包括恰好n 位的整数中有趣的数的个数除以1000000007的余数。 样例输入 4 样例输出 3

    ________________________________________________________________________

    这题插入0、1、2、3的规则我们可以看做是几个状态的相互转化,可以构成一个状态机。首先根据规则我们可以知道第一位数一定是2,我们把只插入2的情况表示为状态0,之后5种不同的状态由这一点发起。共6种状态由如下描述。

    状态0表示出现了2,还未出现0和3,只出现了2,可使用0、2、3。 状态1表示出现了0、2,可使用0、1、2 。状态2表示出现了0、1、2且未出现3,可使用1、2、3 。状态3表示出现了2、3且未出现0,可使用0、3。状态4表示出现了0、2、3,未出现1,可使用0、1、3。 状态5表示出现了0、1、2、3,可使用1、3 。 这6种状态可以构成如下的状态转换图:

    可惜的是,我都已经画出状态转换关系图了,居然还用深度搜索去做,时间果断爆炸才20分,傻到家。有了转换关系我应该立刻想到用动态规划来做。从图中来可以看出,例如恰好n位数的状态5可以由n-1位的状态2添加一个3,状态4添加一个1,状态5添加一个1或者3转换而来,也就是说,n为状态5的数量是n-1位的  状态2+状态4+状态5*2 。有了状态转移方程,问题都迎刃而解。

    先贴出我开始犯傻时用的深搜代码,20分,纪念一下。

    #include<iostream> using namespace std; int n; int num; int set[5];//false表示没有使用过i void DFS(int a,int t,int flag) { bool set_flag = false; if(set[a]==0)//在此之前还位使用过a { set_flag = true; //表示当前是第一次设置了a set[a] = 1; set[4]++; //记录当前使用了几个数 } if((4-set[4])>n-t)//未使用的数的数量小于剩下可加入的数量 { if(set_flag) { set[a]=0; set[4]--; } return ; } if(flag==0) { DFS(2,t+1,0); DFS(0,t+1,1); DFS(3,t+1,3); }else if(flag == 1) { DFS(2,t+1,1); DFS(0,t+1,1); DFS(1,t+1,2); DFS(3,t+1,4); }else if(flag == 2) { DFS(1,t+1,2); DFS(2,t+1,2); DFS(3,t+1,5); }else if(flag == 3) { DFS(0,t+1,4); DFS(3,t+1,3); }else if(flag == 4) { DFS(0,t+1,4); DFS(3,t+1,4); DFS(1,t+1,5); }else{ //到达状态5后可直接计算当前情况下能产生多少不同的解 int temp = n-t,count=1; for(int i=0;i<temp;i++) { count = (count*2)00000007; } num = (num + count)00000007; if(set_flag) { set[a]=0; set[4]--; } return ; } } int main() { cin >> n; DFS(2,1,0); cout << num; return 0; } 下面是用动态规划做的,代码没几行,100分。

    #include<iostream> using namespace std; #define MAXX 1010 #define MOD 1000000007 int n; int num; long long dp[MAXX][6]; int main() { cin >> n; dp[1][0]=1; dp[1][1]=dp[1][2]=dp[1][3]=dp[1][4]=dp[1][5]=0; for(int i=2;i<=n;i++) { dp[i][0] = 1; dp[i][1] = (dp[i-1][1]*2 + dp[i-1][0]) % MOD; dp[i][2] = (dp[i-1][2]*2 + dp[i-1][1]) % MOD; dp[i][3] = (dp[i-1][3] + dp[i-1][0]) % MOD; dp[i][4] = (dp[i-1][4]*2 + dp[i-1][1] + dp[i-1][3]) % MOD; dp[i][5] = (dp[i-1][5]*2 + dp[i-1][2] + dp[i-1][4]) % MOD; } cout << dp[n][5] << endl; return 0; }

    转载请注明原文地址: https://ju.6miu.com/read-33877.html

    最新回复(0)