本題同樣來自caopengcs,只要你有興趣,每個人都可以出題(出題入口在主頁右側邊欄“貢獻題目”->“我要發佈”內),以下是題目詳情:
子序列的定義:對於一個序列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的結果即可)。
首先感謝cp大神,在這一題上有着巨大的幫助,因爲之前理解題意的原因,一直認爲測試點有問題,後來茅塞頓開,終於理解了題意;
題目中的實例有一定的特殊性,假如給的序列爲{1, 1, 4, 1};
則其子序列有“1”,“4”,“1, 1”,“1, 4”,"4, 1","1, 1, 4",“1, 1, 1”,“1, 4, 1”,以及"1, 1, 4, 1"共九種;
如果這個序列沒有重複數據的話,很明顯這就是一個集合的問題了;
不過當出現重複的話,此時的解法就不一樣了:
如果未發生重複現象,則子序列的個數隨着個數的增加,其個數sum[i] = sum[i - 1] + dp[i];此時dp[i] = sum[i - 1];
若之前發生的重複現象,即exist[x] != 0;此時的dp[i]就會發生與之前出現x值重複的組合,此時dp[i] = sum[i - 1]; dp[i] -= sum[exist[x] - 1];
繼續深究,貼個代碼:
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
const int M = 1000000007;
using namespace std;
int run(const int *a, int n) {
int exist[111] = {0}; //判斷是否存在,數組元素0<=a[i]<=110
int dp[101] = {0};
int sum[101] = {1}; //個數
int x;
for (int i = 1; i <= n; ++i)
{
x = a[i - 1]; //一個一個讀取元素
dp[i] = sum[i - 1]; //
if (exist[x] != 0 )
{
dp[i] -= sum[exist[x] - 1]; //之前出過此值,出現重複
if(dp[i] < 0)
dp[i] += M;
}
exist[x] = i; //記錄最近出現x的下標
sum[i] = sum[i - 1] + dp[i]; //更新子序列個數
if (sum[i] >= M) //超限則進行-M,重新在表示範圍內
{
sum[i] -= M;
}
}
if (--sum[n] < 0) //-1
{
sum[n] += M;
}
return sum[n];
}
//start 提示:自動閱卷起始唯一標識,請勿刪除或增加。
int main()
{
int a[] = {1, 1, 4, 1};
int length = sizeof(a) / sizeof(int);
cout<<run(a, length);
return 0;
}
//end //提示:自動閱卷結束唯一標識,請勿刪除或增加。
多多交流...o(∩_∩)o