降雷皇 题解

题面:

【问题描述】
降雷皇哈蒙很喜欢雷电,他想找到神奇的电光。
哈蒙有\(n\)条导线排成一排,每条导线有一个电阻值,神奇的电光只能从一根导线传到电阻比它大的上面,而且必须从左边向右传导,当然导线不必是连续的。
哈蒙想知道电光最多能通过多少条导线,还想知道这样的方案有多少。
【输入格式】
第一行两个整数\(n\)\(type\)\(type\)表示数据类型
第二行\(n\)个整数表示电阻。

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

【样例输入输出】
hamon.in
5 1
1 3 2 5 4
hamon.out
3
4

【数据范围与约定】
对于\(20\%\)的数据\(n \le 10\)
对于\(40\%\)的数据\(n \le 1000\)
对于另外\(20\%\)的数据\(type=0\)
对于另外\(20\%\)的数据保证最多能通过不超过\(100\)条导线;
对于\(100\%\)的数据\(n \le 100000\),电阻值不超过\(10000\)

解析:

这是一道模板题。XD

如何去维护LIS?

令以第\(n\)个数结尾的LIS长度为\(f_i\),易得\(f_i=\max\limits_{j=1}^{i-1}f_j+1\)
本来需要遍历每一个\(j\),可是发现树状数组可以维护满足结合律的操作(如区间和,区间积,区间异或,区间最值等),复杂度可以降到\(O(\log n)\)
于是总复杂度为\(O(n \log n)\)

如何去维护LIS个数?

\(g_i\)为长度为\(f_i\)的LIS的方案数,显然有:

\[g_i=\max \left(1,\sum_{i

可以用树状数组顺带维护一下(区间和)。

代码:

#include
using namespace std;
#define rep(i,a,b) for(register long long i=a;i<=b;++i)
inline long long read()
{
    bool f=0;long long x=0;char ch;
    do{ch=getchar();f|=(ch=='-');}while(!isdigit(ch));
    do{x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}while(isdigit(ch));
    return f?-x:x;
}
inline void write(long long x)
{
    if(x<0)x=-x,putchar('-');
    if(x>9)write(x/10);putchar(x%10+'0');
}
inline void writesp(long long x)
{
	write(x);putchar(' ');
}
inline void writeln(long long x)
{
	write(x);puts("");
}
const long long mod=123456789,maxn=4e5;
long long n,type;
long long a[100001];
long long tr[maxn],val[maxn],mx;
pair ans,temp;
inline long long lowbit(long long x){return x&-x;}
void add(long long x,long long w,long long sz)
{
    for(register long long i=x;i<=maxn;i+=lowbit(i))
    {
		if(w>val[i]){tr[i]=sz;val[i]=w;}
        else if(w==val[i])tr[i]=(tr[i]+sz)%mod;
    }
}
pair ask(long long x)
{
    pair res(0,0);
    for(register long long i=x;i;i-=lowbit(i))
        if(val[i]>res.first)res=make_pair(val[i],tr[i]);
        else if(val[i]==res.first)res=make_pair(res.first,(res.second+tr[i])%mod);
    return res;
}
int main()
{
	n=read(),type=read();
    add(1,0,1);
    rep(i,1,n)
    {
    	a[i]=read()+1;
        temp=ask(a[i]);
        add(a[i]+1,temp.first+1,temp.second);
        mx=max(mx,a[i]+1);
    }
    ans=ask(mx);
    writeln(ans.first);
    if(type)writeln(ans.second);
    return 0;
}

你可能感兴趣的:(降雷皇 题解)