[2017雅礼集训]day10 T2 数列 最长上升子序列

可以发现最后的最长上升子序列是由原序列中从某一个点开始的最长上升子序列A和最长下降子序列B组合而成的,贡献的方案数为numA *numB。注意找到更长的以后要把原来的方案数清零。
假设最终最长长度为R,最后答案要乘上2^(N-R),因为其他元素可以任意选择放左边或右边。
求最长上升/下降子序列及方案数可以用树状数组做。经典的dp方程:F[i]=max{F[j]+1}(a[i]

type
  node=record
    t,s:int64;
  end;
var
  n,i,j:longint;
  last,size,lq,ans1,ans2:int64;
  a,b:array[0..500100]of int64;
  c,l:array[0..500100]of node;
  f1,g1,f2,g2:array[0..500100]of int64;
  o:node;
const md=1000000007;
function max(x,y:int64):int64;
begin
  if x>y then exit(y)
  else exit(x);
end;
procedure qs(p,q:longint);
var
  i,j:longint;
  mid:int64;
  tt:node;
begin
  mid:=l[(p+q)div 2].t;
  i:=p;
  j:=q;
  repeat
    while l[i].tdo inc(i);
    while l[j].t>mid do dec(j);
    if i<=j then
    begin
      tt:=l[i];
      l[i]:=l[j];
      l[j]:=tt;
      inc(i);
      dec(j);
    end;
  until i>j;
  if pthen qs(p,j);
  if ithen qs(i,q);
end;
function lowbit(x:longint):longint;
begin
  exit(x and(-x));
end;
function getmax(x:int64):node;
begin
  getmax.t:=0;
  getmax.s:=1;
  while x>0 do
  begin
    if c[x].t=getmax.t then getmax.s:=(getmax.s+c[x].s)mod md;
    if c[x].t>getmax.t then begin getmax.t:=c[x].t; getmax.s:=c[x].s; end;
    x:=x-lowbit(x);
  end;
end;
procedure updata(x,y,z:int64);
begin
  while x<=size do
  begin
    if c[x].t=y then c[x].s:=(c[x].s+z)mod md;
    if c[x].tthen begin c[x].t:=y; c[x].s:=z; end;
    x:=x+lowbit(x);
  end;
end;
function ksm(a,b:int64):int64;
begin
  ksm:=1;
  while b>0 do
  begin
    if b mod 2=1 then ksm:=(ksm*a)mod md;
    a:=(a*a)mod md;
    b:=b div 2;
  end;
end;
begin
  readln(n);
  for i:=1 to n do
  begin
    read(a[i]);
    l[i].t:=a[i];
    l[i].s:=i;
  end;
  qs(1,n);
  last:=0;
  lq:=0;
  for i:=1 to n do
    if l[i].t=last then a[n-l[i].s+1]:=lq
    else
    begin
      last:=l[i].t;
      inc(lq);
      a[n-l[i].s+1]:=lq;
    end;
  size:=lq;
  fillchar(c,sizeof(c),0);
  for i:=1 to n do
  begin
    o:=getmax(a[i]-1);
    f1[i]:=o.t+1;
    g1[i]:=o.s;
    updata(a[i],f1[i],g1[i]);
  end;
  fillchar(c,sizeof(c),0);
  for i:=1 to n do
  begin
    o:=getmax(size-a[i]);
    f2[i]:=o.t+1;
    g2[i]:=o.s;
    updata(size-a[i]+1,f2[i],g2[i]);
  end;

  ans1:=0;
  ans2:=0;
  for i:=1 to n do
  begin
    if f1[i]+f2[i]-1=ans1 then ans2:=(ans2+(g1[i]*g2[i])mod md)mod md;
    if f1[i]+f2[i]-1>ans1 then begin ans1:=f1[i]+f2[i]-1; ans2:=(g1[i]*g2[i])mod md; end;
  end;
  ans2:=(ans2*ksm(2,n-ans1))mod md;
  writeln(ans1,' ',ans2);
end.

你可能感兴趣的:(最长上升子序列)