LIS求方案,求别犯sb错误
降雷皇

问题描述

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

输入格式

第一行两个整数 $n $ 和 $type $。 $type $ 表示数据类型
第二行 $n $ 个整数表示电阻。

输出格式

第一行一个整数表示电光最多能通过多少条导线。
如果 $type=1 $ 则需要输出第二行, 表示方案数, 对 $123456789 $ 取模。

数据范围与约定

对于 $20% $ 的数据 $n\le 10 $;
对于 $40% $ 的数据 $n\le 1000 $;
对于另外 $20% $ 的数据 $type=0 $;
对于另外 $ 20% $ 的数据保证最多能通过不超过 $100 $ 条导线;
对于 $100% $ 的数据 $n\le 100000 $,电阻值不超过 $100000 $。


简单的 \(\tt{LIS}\)求方案的煞笔题,又挂了...写篇博客记录一下。

我是直接把方案和最大值放一个结构体里了,线段树的节点值域代表电阻值。

然后我以为电阻值小于 $n $,挂分点 $1 $

因为每次查询的是 $r-1 $,所以线段树上要搞 \(0\)节点,挂分点 $2 $


Code:

#include <cstdio>
const int N=1e5;
const int mod=123456789;
int n,typ;
struct node
{
    int mx,cnt;
    node(){mx=cnt=0;}
    node friend operator +(node n1,node n2)
    {
        node n3;
        if(n1.mx==n2.mx)
        {
            n3.mx=n1.mx,n3.cnt=(n1.cnt+n2.cnt)%mod;
            if(n3.mx==0) n3.cnt=1;
            return n3;
        }
        return n1.mx>n2.mx?n1:n2;
    }
}mx[(N+10)<<2],dp[N+10],ans;
#define ls id<<1
#define rs id<<1|1
void build(int id,int l,int r)
{
    mx[id].cnt=1;
    if(l==r) return;
    int mid=l+r>>1;
    build(ls,l,mid),build(rs,mid+1,r);
}
void change(int id,int l,int r,int p,node d)
{
    if(l==r)
    {
        mx[id]=mx[id]+d;
        return;
    }
    int mid=l+r>>1;
    if(p<=mid) change(ls,l,mid,p,d);
    else change(rs,mid+1,r,p,d);
    mx[id]=mx[ls]+mx[rs];
}
node query(int id,int l,int r,int p)
{
    if(l==r) return mx[id];
    int mid=l+r>>1;
    if(p<=mid) return query(ls,l,mid,p);
    else return mx[ls]+query(rs,mid+1,r,p);
}
int main()
{
    scanf("%d%d",&n,&typ);
    build(1,0,N);
    for(int r,i=1;i<=n;i++)
    {
        scanf("%d",&r);
        dp[i]=query(1,0,N,r-1);
        dp[i].mx++;
        change(1,0,N,r,dp[i]);
    }
    ans=query(1,0,N,N);
    printf("%d\n",ans.mx);
    if(typ) printf("%d\n",ans.cnt);
    return 0;
}

2018.11.1