【JZOJ4920】降雷皇
Description
降雷皇哈蒙很喜欢雷电,他想找到神奇的电光。
哈蒙有n条导线排成一排,每条导线有一个电阻值,神奇的电光只能从一根导线传到电阻比它大的上面,而且必须从左边向右传导,当然导线不必是连续的。
哈蒙想知道电光最多能通过多少条导线,还想知道这样的方案有多少。
简单来说就是给出一个序列,求该序列最长上升子序列的长度和方案数。
给出type,表示数据类型。type=1表示需要在第二行输出方案数。
有20%的数据type=0
Solution
首先设
Fi
表示以
i
为结尾的最长上升子序列的长度,
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);
}
}