算法訓練 K好數

問題描述

如果一個自然數N的K進製表示中任意的相鄰的兩位都不是相鄰的數字,那麼我們就說這個數是K好數。求L位K進制數中K好數的數目。例如K = 4,L = 2的時候,所有K好數爲11、13、20、22、30、31、33 共7個。由於這個數目很大,請你輸出它對1000000007取模後的值。

輸入格式

輸入包含兩個正整數,K和L。

輸出格式

輸出一個整數,表示答案對1000000007取模後的值。

樣例輸入

4 2

樣例輸出

7

數據規模與約定

對於30%的數據,KL <= 106;

對於50%的數據,K <= 16, L <= 10;

對於100%的數據,1 <= K,L <= 100。

思路解析

這是一道動態規劃題目,想到了思路其實特別簡單。
首先我不好直接解決長度爲L的K好數有幾種可能性。但是可以通過求出長度爲L-1的K好數的數目再此基礎上往末尾再添一位符合題目條件的數即可。
例如4進制的3位K好數,末尾位是2的可能性m[3][2]=m[2][0]+m[2][2]。m[2][2]=m[1][0]+m[1][2],由此可以總結出遞推方程如下:

設表示K進制i位K好數其末尾位是j的所有可能性是m[i][j]
則:
在這裏插入圖片描述

代碼

#include <iostream>
using namespace std;
#include<stdio.h>
#include<stdlib.h>
#include<cstring>
#include<math.h>
//動態規劃
//用m[i][j]來表示長度爲i的末尾爲j的所有可能性數
//長度爲0的末尾爲j的m[0][j]=0;
//長度爲0的末尾爲j的m[1][j]=1(m[1][0]=0除外);
//體現不斷往末尾加一位的思想,加的這一位不能是其前一位的相鄰的數
//從m[i-1][j]到m[i][j]:m[i][j]=m[i-1][k](其中|k-j|!=1);
//最後結果sum=所有m[L][0...K-1]之和
long long m[101][101];
int main()
{
   memset(m,0,sizeof(m));
   int K,L;//K表示K進制,L表示L位數
   cin>>K>>L;
   //長度爲0的末尾爲j的m[0][j]=0;
   for(int j=0;j<=K-1;j++)
      m[0][j]=0;
   //長度爲0的末尾爲j的m[1][j]=1(m[1][0]=0除外);
   m[1][0]=0;
   for(int j=1;j<=K-1;j++)
       m[1][j]=1;
   //開始規劃
   for(int i=1;i<=L;i++)//最後要求的長度爲L
   for(int j=0;j<=K-1;j++){//每一位的取值可以是0-(K-1)
      for(int t=0;t<=K-1;t++)//往末尾加一位的可能取值也是0-(K-1)
        if(t-j!=-1&&t-j!=1){
             m[i][j]=m[i][j]+m[i-1][t];
             m[i][j]=m[i][j]%1000000007;//以防整數過大取餘
        }
   }
   long long sum;//定義結果
   sum=0;
   //sum的值爲數組m的第L行的從0-(K-1)所有元素之和
   for(int i=0;i<=K-1;i++){
     sum=sum+m[L][i];
     sum=sum%1000000007;//以防整數過大取餘
   }
   cout<<sum;
   return 0;
}

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章