[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)$ imes (2+2=4,)dp_3(=(1+4)) imes(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;
  }
原文地址:https://www.cnblogs.com/stepsys/p/10387978.html