子序列的個數
題目詳情: 子序列的定義:對於一個序列a=a[1],a[2],......a[n],則非空序列a'=a[p1],a[p2]......a[pm]為a的一個子序列,其中1<=p1<p2<.....<pm<=n。
例如:4,14,2,3和14,1,2,3都為4,13,14,1,2,3的子序列。 對於給出序列a,有些子序列可能是相同的,這里只算做1個,要求輸出a的不同子序列的數量。
輸入: 長度為n的數組1<=n<=100,數組元素0<=a[i]<=110
輸出:子序列 的個數對1000000007取余數的結果(由於答案比較大,輸出Mod 1000000007的結果即可)。
函數頭部: C/C++: int run(cons int *a,int n); java public static int run(int [] a);
這道題目也是困擾了我很久,一直找不到比較好的方法,這道題目應該是可以用動態規划做出來的,因此我也特地去學習動態規划的思想,並找了一些練習題做,可是這個狀態轉移方程着實難住我了,本來數學基礎一般般,這就更加大了難度。雖然我最終解決了這道題目,可是那是建立在大神指點的情況下做出來的,我在這里只是把題解寫出來,順便裨補闕漏,看看自己的理解是否正確,其實,想和做是兩回事,這里也請大家給與指正。
題解:
假設子序列的前k個數的子序列個數為d(k),那么前k - 1個子序列的個數就為d(k - 1)個子序列,從k - 1 到k的變化是怎樣的呢?
1、假設數組a[N]第k個數為a[k],如果a[k] 與前面的k - 1個數都不相同,那么就有 : d(k) = d(k - 1) + 【d(k - 1) + 1】 = 2d(k - 1) + 1,為什么呢?可以這樣想,對於前k- 1項的子序列個數為d(k - 1),那前k個數,無非就是在前k - 1項的基礎上多加了一個數a[k](a[k]與前k - 1個數任意一個都相等),那就在原來的組合上加上a[k],就有d(k - 1)個,還有一個a[k]自己構成一個子序列,所以還要加1;
2、假設a[k] 與前面的k - 1個數其中一個相等,那依舊加上前k - 1個子序列個數 d(k - 1),但是由於前面有與a[k]相等的數,所以要減掉重復的部分,如何找到重復的部分呢,假設離k最近的一個與a[k]相等的數為第t個a[t] = a[k],即序列(a[1], a[2], ……,a[t],……,a[k - 1],a[k]),a[t] = a[k];我們已經知道序列(a[1], a[2], ……,a[t])的序列個數為d(t),那么d(t - 1)就是重復的部分,這里需要自己做好思考,也是算法的關鍵部分,這里我要解釋的地方是,為什么只需要找到離k最近的t使得a[t] = a[k]?給出的解釋是:我們是從1 - n對數組進行遍歷的,計算d(i)的i就是從1到n依次計算的,那么第一次遇到a[k] = a[t]的情況滿足條件:有且僅有一個t使得a[t] = a[k],比如序列(1, 2, 3, 2, 4, 2),分別計算d(1),d(2),d(3),d(4),d(5),d(6);我們在計算d(4)的時候發現a[4] = a[2](假設下標從1開始),所以d(4) = 2*d(3) - d(2 -1) = 2d(3) - d(1);當計算d(6)的時候也有a[6] = a[4] = a[2],但是由於我們前面已經把a[2]重復的部分減掉了,所以不需要再減,d(6) = 2 * d(5) - d(4 - 1) = 2d(5) - d(3).
過程繁瑣,我總結一下結論:
狀態轉移方程為:
d(k) = 2 * d(k - 1) + 1; a[k] != a[i],i = 1,2,3……k - 1;
d(k) = 2 * d(k - 1) - d(t - 1); 從k往前搜索,存在離k最近的t,使得a[t] = a[k].
狀態轉移方程分析出來的話,剩下的基本就是小菜一碟了,代碼如下:

/* 以下是題目詳情: 子序列的定義:對於一個序列a=a[1],a[2],......a[n], 則非空序列a'=a[p1],a[p2]......a[pm]為a的一個子序列,其中1<=p1<p2<.....<pm<=n。 例如:4,14,2,3和14,1,2,3都為4,13,14,1,2,3的子序列。 對於給出序列a,有些子序列可能是相同的, 這里只算做1個,要求輸出a的不同子序列的數量。 輸入: 長度為n的數組1<=n<=100,數組元素0<=a[i]<=110 輸出:子序列 的個數對1000000007取余數的結果(由於答案比較大,輸出Mod 1000000007的結果即可)。 函數頭部: C/C++: int run(cons int *a,int n); java public static int run(int [] a); */ #include <stdio.h> #include <stdlib.h> #define M 1000000007 int run(const int *a,int n) { long long SubArray[120] = {0}; int LastIndex[120] = {0}; int iter = 0; for(iter = 1; iter <= n; iter++) { switch(LastIndex[a[iter - 1]]) { case 0: { SubArray[iter] = (2 * SubArray[iter - 1] + 1) % M; break; } default: { SubArray[iter] = (2 * SubArray[iter - 1] - SubArray[LastIndex[a[iter - 1]] - 1] + M) % M; break; } } LastIndex[a[iter - 1]] = iter; } return SubArray[n] % M; } int main(void) { //int a[5] = {1, 2, 2, 3 ,3}; int a[4] = {1, 2, 3 , 2}; printf("the result is %d\n", run(a, 4)); return 0; }