2018"百度之星"程序设计大赛 - 资格赛-1005 序列计数

20 篇文章 0 订阅
4 篇文章 0 订阅

思路:dp[i][k]表示:以a[i]为右端点时长度为k的上升子序列的个数,转换公式比较容易写出来

dp[i][k]=sum{dp[j][k-1]} (a[j]<a[i],j<i)

可以看出有 i,j,k三重循环,时间复杂度为 O(n^3) 会TLE,因此看能不能减小一重循环

又转换方程看出,dp[i][k]为前i-1个a[j]<a[i]的总和,有a[j]<a[i]才能求和,因此可以考虑用树状数组来求和。

遍历排列a[i],用树状数组记录前 a[i] 的总和,则 dp[i][k]=Query(a[i]-1),而dp[i][k]又可以用dp[i]来代替,对于树状数组C[i]的处理,可用d[a[i]]保存a[i]的上升子序列个数,在计算d[a[i]]时先将其重置树状数组

Code :

#include<iostream>
using namespace std;
typedef long long LL;

const int MOD=1e9+7;
const int MAX_N=10005;
int n,T;
int a[MAX_N],d[MAX_N];
LL C[MAX_N];
int ans[MAX_N];

int Lowbit(int x);
void Update(int id,int x);
LL Query(int id);
int main()
{
	ios::sync_with_stdio(false);
	cin>>T;
	for(int t=1;t<=T;++t)
	{
		cin>>n;
		for(int i=1;i<=n;d[i]=1,ans[i]=0,++i)
			cin>>a[i];
		ans[1]=n;
		for(int k=2;k<=n;++k)
		{
			for(int i=1;i<=n;++i)
				C[i]=0;
			LL sum=0;
			for(int i=1;i<=n;++i)
			{
				Update(a[i],d[a[i]]);
				d[a[i]]=Query(a[i]-1)%MOD;
				sum+=d[a[i]];
			}
			ans[k]=sum%MOD;
			if(!ans[k])	break;
		}
		cout<<"Case #"<<t<<":";
		for(int i=1;i<=n;++i)
			cout<<" "<<ans[i];
		cout<<endl;
	}
	
	return 0;
}

int Lowbit(int x)
{
	return x&(-x);
}

void Update(int id,int x)
{
	while(id<=n){
		C[id]+=x;
		id+=Lowbit(id);
	}
}

LL Query(int id)
{
	LL ans=0;
	while(id>0){
		ans+=C[id];
		id-=Lowbit(id);
	}
	return ans;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值