[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;
  }

转载于:https://www.cnblogs.com/stepsys/p/10387978.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值