51Nod 1202 子序列個數(簡單計數dp)
阿新 • • 發佈:2019-02-17
收藏
關注
子序列的定義:對於一個序列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的不同子序列的數量。由於答案比較大,輸出Mod 10^9 + 7的結果即可。
Input
Output
第1行:一個數N,表示序列的長度(1 <= N <= 100000) 第2 - N + 1行:序列中的元素(1 <= a[i] <= 100000)
輸出a的不同子序列的數量Mod 10^9 + 7。Input示例
4 1 2 3 2Output示例
13
題解:我們知道如果不存在重複的數,那麼dp[i]=dp[i-1]*2(含空集的情況)。現在考慮出現了重複的數。比如當前要取的數為a[i],且a[i]最近一次在之前的j位置出現過了。那麼有dp[i]=dp[i-1]*2-dp[j-1]。所以我們利用一個數組mark記錄下a[i]出現的位置就好了,沒有出現過為0。
注意:在運算中會出現減的情況,所以取模是要加上mod
程式碼如下:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define maxn 100010 #define mod 1000000007 long long dp[maxn]; int a[maxn]; int mark[maxn];//利用hash記錄a[i]前面是否出現了一次,並記錄下上一次出現的位置 int main() { int n,i,j; while(scanf("%d",&n)!=EOF) { for(i=1;i<=n;++i) scanf("%d",&a[i]); memset(dp,0,sizeof(dp)); memset(mark,0,sizeof(mark)); dp[0]=1; for(i=1;i<=n;++i) { if(mark[a[i]]==0) dp[i]=(dp[i-1]*2)%mod; else dp[i]=(2*dp[i-1]-dp[mark[a[i]]-1]+mod)%mod; mark[a[i]]=i; } printf("%lld\n",dp[n]-1); } return 0; }