【NOIP2018复习】排列(树状数组/线段树)

本文详细解析了1187号排列问题,探讨了如何通过树状数组统计上升子序列个数的方法,适用于特定长度的随机排列,提供了一种高效的算法解决方案。

1187.排列

时间限制:10000MS内存限制:256000KB

题目描述

现在有一个随机排列,你需要对所有的k∈[1,n],求出长度为k的上升子序列个数
 

输入

第一行包含一个整数 T,表示有 T 组测试数据。
接下来依次描述 T 组测试数据。对于每组测试数据:
第一行包含一个整数 n,表示排列的长度。
第二行包含 n 个整数
除了样例,你可以认为给定的排列是从所有 1,2,…,n 的排列中等概率随机选出的。

输出

对于每组测试数据,输出取模(1000000007)后的答案,相邻的两个数中间用一个空格隔开,行末不要有多余空格。

输入样例复制

2
4
1 2 3 4
4
1 3 2 4

输出样例复制

4 6 4 1
4 5 2 0

说明

30%数据满足 T<=1, n<=1e2 70% T<=10, n<=1e3 100% T<=10, n<=1e4

题解:对于第i个数,最长上升子序列是a[j]<a[i],j<i的数量
          因为i是从小到大枚举,i有序,只需用树状数组统计a[i]前小于a[i]的数量皆可
          

const

  maxn=10000;

  p=1000000007;

  inf='1022T3.in';

var

  a:array[1..maxn]of int64;

  c:array[1..maxn]of int64;

  f:array[1..300,1..maxn]of longint;

  t,n,i,j,ans,kk,hh:longint;

procedure init;

var

  i:longint;

begin

  readln(n);

  fillchar(f,sizeof(f),0);

  for i:=1 to n do

  begin

    read(a[i]);

    f[1,i]:=1;

  end;

  readln;

end;

function lowbit(x:longint):longint;

begin

  lowbit:=x and -x;

end;

function ask(x:longint):longint;

var

  i:longint;

begin

  i:=x;

  ask:=0;

  while i>0 do

  begin

    ask:=(ask+c[i])mod p;

    i:=i-lowbit(i);

  end;

end;

procedure change(x,y:longint);

var

  i:longint;

begin

  i:=x;

  while i<=10000 do

  begin

    c[i]:=(c[i]+y) mod p;

    i:=i+lowbit(i);

  end;

end;

begin

 // assign(input,inf);reset(input);

  readln(t);

  for kk:=1 to t do

  begin

    init;

    write(n,' ');

    for i:=2 to n do

    begin

      fillchar(c,sizeof(c),0);

      ans:=0;

      for j:=1 to n do

      begin

        f[i,j]:=ask(a[j]-1)mod p;

        change(a[j],f[i-1,j]);

        ans:=(ans+f[i,j])mod p;

      end;

      write(ans);

      if i<>n then write(' ');

      hh:=i;

      if ans=0 then break;

    end;

    for i:=hh+1 to n do

    begin

      write(0);

      if i<>n then write(' ');

    end;

    writeln;

  end;

  //close(input);

end.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值