Codeforces 315E Sereja and Subsequences【思维+Dp】

351 篇文章 2 订阅

E. Sereja and Subsequences
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Sereja has a sequence that consists of n positive integers, a1, a2, ..., an.

First Sereja took a piece of squared paper and wrote all distinct non-empty non-decreasing subsequences of sequence a. Then for each sequence written on the squared paper, Sereja wrote on a piece of lines paper all sequences that do not exceed it.

A sequence of positive integers x = x1, x2, ..., xr doesn't exceed a sequence of positive integers y = y1, y2, ..., yr, if the following inequation holds: x1 ≤ y1, x2 ≤ y2, ..., xr ≤ yr.

Now Sereja wonders, how many sequences are written on the lines piece of paper. Help Sereja, find the required quantity modulo 1000000007 (109 + 7).

Input

The first line contains integer n (1 ≤ n ≤ 105). The second line contains n integers a1, a2, ..., an (1 ≤ ai ≤ 106).

Output

In the single line print the answer to the problem modulo 1000000007 (109 + 7).

Examples
input
1
42
output
42
input
3
1 2 2
output
13
input
5
1 2 3 4 5
output
719

题目大意:


求所有的非递减子串的价值和(子串需要保证没有重复数字),一个子串的价值为子串所有数字的乘积。


思路:


设定Dp【i】,表示以位子i作为子串的结尾能够获得的价值和。

那么有:Dp【i】=ΣDp【j】*Dp【i】+Dp【i】,这里需要保证a【j】<=a【i】,那么这里我们可以用树状数组加速转移。

因为子串需要保证没有重复数字,那么我们需要去重,Dp【i】-=Pre【a【i】】,pre【a【i】】表示上一次a【i】出现的位子能够提供的价值。

过程维护一下即可。

注意取模、


Ac代码:

#include<stdio.h>
#include<string.h>
using namespace std;
#define ll __int64
/**************************************/
ll n;
ll mod = 1000000000+7;
ll tree[3000005];//树
ll lowbit(ll x)//lowbit
{
    return x&(-x);
}
ll sum(ll x)
{
    ll sum=0;
    while(x>0)
    {
        sum+=tree[x];
        sum%=mod;
        x-=lowbit(x);
    }
    return sum;
}
ll add(ll x,ll c)
{
    while(x<=1000000+50)
    {
        tree[x]+=c;
        tree[x]%=mod;
        x+=lowbit(x);
    }
}
/**************************************/
ll a[1050000];
ll dp[1050000];
ll pre[1050000];
int main()
{
    while(~scanf("%I64d",&n))
    {
        ll ans=0;
        memset(tree,0,sizeof(tree));
        memset(pre,-1,sizeof(pre));
        memset(dp,0,sizeof(dp));
        for(ll i=1;i<=n;i++)scanf("%I64d",&a[i]);
        for(ll i=1;i<=n;i++)
        {
            dp[i]=sum(a[i])*a[i]+a[i];
            if(pre[a[i]]!=-1)dp[i]-=pre[a[i]];
            dp[i]=(dp[i]%mod+mod)%mod;
            ans+=dp[i];
            ans=(ans%mod+mod)%mod;
            pre[a[i]]=sum(a[i])*a[i]+a[i];
            add(a[i],dp[i]);
        }
        printf("%I64d\n",(ans%mod+mod)%mod);
    }
}








  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值