【JZOJ4920】降雷皇

Description

降雷皇哈蒙很喜欢雷电,他想找到神奇的电光。
哈蒙有n条导线排成一排,每条导线有一个电阻值,神奇的电光只能从一根导线传到电阻比它大的上面,而且必须从左边向右传导,当然导线不必是连续的。
哈蒙想知道电光最多能通过多少条导线,还想知道这样的方案有多少。

简单来说就是给出一个序列,求该序列最长上升子序列的长度和方案数。

给出type,表示数据类型。type=1表示需要在第二行输出方案数。

有20%的数据type=0

Solution

首先设 Fi 表示以 i 为结尾的最长上升子序列的长度,Gi表示方案数。

Fi 可以扔进树状数组,权值线段树里求。

然后是 Gi ,那么很显然有这样一个方程:

Gi=max(1,j<i,Fi=Fj+1,aj<aiGj)

于是,我们同样用树状数组(或权值线段树)来优化即可。

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define ll long long
#define N 100001
#define mo 123456789
using namespace std;
int f[N],a[N];
ll g[N];
int mx;
int fz=0;
ll gz=0;
struct node{
    int f;
    ll g;
}tr[N*4];
void update(int v)
{
    tr[v].f=max(tr[v*2].f,tr[v*2+1].f);
    if(tr[v*2].f>tr[v*2+1].f) tr[v].g=tr[v*2].g;
    else if(tr[v*2].f<tr[v*2+1].f) tr[v].g=tr[v*2+1].g;
    else tr[v].g=(tr[v*2].g+tr[v*2+1].g)%mo;
}
void insert(int v,int l,int r,int x,int ff,ll gg)
{
    if(l==r)
    {
        if(tr[v].f<ff) tr[v].g=gg;
        else if(tr[v].f==ff) (tr[v].g+=gg)%=mo;
        tr[v].f=max(tr[v].f,ff);
        return;
    }
    int mid=(l+r)/2;
    if(x<=mid) insert(v*2,l,mid,x,ff,gg);
    else insert(v*2+1,mid+1,r,x,ff,gg);
    update(v);
}
void find(int v,int l,int r,int x,int y)
{
    if(l==x && r==y)
    {
        if(fz<tr[v].f) fz=tr[v].f,gz=tr[v].g;
        else if(fz==tr[v].f) (gz+=tr[v].g)%=mo;
        return;
    }
    int mid=(l+r)/2;
    if(y<=mid) find(v*2,l,mid,x,y);
    else if(x>mid) find(v*2,mid+1,r,x,y);
    else
    {
        find(v*2,l,mid,x,mid);
        find(v*2+1,mid+1,r,mid+1,y);
    }
}
int main()
{
    freopen("hamon.in","r",stdin);
    freopen("hamon.out","w",stdout);
    int n,t;
    scanf("%d %d",&n,&t);
    fo(i,1,n) scanf("%d",&a[i]),mx=max(mx,a[i]);
    int p=1;
    f[1]=1;
    g[1]=1;
    insert(1,1,mx,a[1],f[1],g[1]);
    fo(i,2,n)
    {
        fz=gz=0;
        if(a[i]>=2) find(1,1,mx,1,a[i]-1);
        f[i]=fz+1;
        g[i]=max(1ll,gz);
        p=max(p,f[i]);
        insert(1,1,mx,a[i],f[i],g[i]);
    }
    printf("%d\n",p);
    if(t==1)
    {
        fz=gz=0;
        find(1,1,mx,1,mx);
        printf("%lld",gz);
    }
}
posted @ 2016-12-12 19:27  sadstone  阅读(99)  评论(0编辑  收藏  举报