[CF314C](Sereja and Subsequences)
-
题意
给你一个序列
把这个序列的每一个不下降子序列拿出来
对于每一个子序列,一个可行序列为:
1.由正整数组成,长度和原子串相同
2.不大于原子串
求所有,所有的可行串
-
solution
dp
设\(dp_i\)为以i为结尾的所有可行串的总数
对于最简单的严格单调递增序列有(即样例2)
\(dp_i\)=( \(\sum^{i-1}_{r=1}\) \(dp_r\))*\(dp_i\)+\(dp_i\)
但是重复怎么办?
我们减去上一个重复点的dp值(推荐手模一下以便理解)
举个例子
3
1 2 2
这个序列,\(dp_1\)=1,\(dp_2\)=(1)$\times \(2+2=4,\)dp_3\(=(1+4)\)\times\(2+2-\)dp_2$=8
但是序列递减部分怎么办,不加就可以了嘛qwq
但是时间复杂度\(n^2\)怎么办(syk:还不简单),用树状数组维护一下就降下来辣
如上
-
code
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define int long long
#define lowbit(x) (x&-x)
using namespace std;
const int mod=1000000007;
int tree[2000005*4];
int dp[2000005];
int from[2000005];//from 即上一个重复点的dp值
int a[200005];
int n,poss=1,ans=0;
void add(int x,int k) {for(x;x<=2000000;x+=lowbit(x))tree[x]+=k,tree[x]%=mod;}
int sum(int k) {
int anss=0;
for(k;k;k-=lowbit(k))anss+=tree[k],anss=(anss%mod+mod)%mod;
return anss;
}
signed main(){
scanf("%lld",&n);
memset(from,-1,sizeof(from));
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
for(int i=1;i<=n;i++){
dp[i]=(sum(a[i])*a[i]%mod+a[i])%mod;//sum(a[i])这样就可以保证加的都是小于等于a[i]的
if(from[a[i]]!=-1)dp[i]-=from[a[i]];
dp[i]=(dp[i]%mod+mod)%mod;
ans+=dp[i];
ans=(ans%mod+mod)%mod;
from[a[i]]=(sum(a[i])*a[i]+a[i])%mod;
add(a[i],dp[i]);//注意传的是a[i]而不是i
}
cout<<ans%mod;
}