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.
本文详细解析了1187号排列问题,探讨了如何通过树状数组统计上升子序列个数的方法,适用于特定长度的随机排列,提供了一种高效的算法解决方案。
&spm=1001.2101.3001.5002&articleId=83745157&d=1&t=3&u=edb65287215248e98e0cc21cfbf089e1)
381

被折叠的 条评论
为什么被折叠?



