ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[ybtoj 4.2.3 /UVA12983] The Battle of Chibi

2021-06-11 20:05:42  阅读:177  来源: 互联网

标签:cnt int ybtoj tree Chibi add 序列 Battle leqslant


题意

在一个长度为 n n n 的序列中找到长度为 m m m 的严格上升子序列的个数 ,答案对 1 0 9 + 7 10^9+7 109+7 取模。 1 ⩽ n , m ⩽ 1 0 3 1\leqslant n,m \leqslant 10^3 1⩽n,m⩽103

思路

设 f [ i ] [ j ] f[i][j] f[i][j] 表示长度为 i i i,以 j j j 结尾的子序列的数量,可以列得方程
f [ i ] [ j ] = ∑ k < j f [ i − 1 ] [ k ] f[i][j]=\sum_{k<j}{f[i-1][k]} f[i][j]=k<j∑​f[i−1][k]
离散化后直接做的话是 O ( m n 2 ) O(mn^2) O(mn2) 的,不可接受。
考虑优化计算方式。
注意到这里的计算相当于统计 f [ i − 1 ] f[i-1] f[i−1] 的前缀和,
题目就转化为要求实现快速求前缀和,可以用树状数组来维护。
复杂度就被降为 O ( m n log ⁡ n ) O(mn\log n) O(mnlogn)

代码

#include<bits/stdc++.h>
#define N 1010
#define mod 1000000007
using namespace std;
int tree[N][N],a[N],b[N],n,m,tmp,tot,ans,T;
void add(int id,int x,int num){for(;x<=tot;x+=x&-x)tree[id][x]=(tree[id][x]+num)%mod;}
int ask(int id,int x){int cnt=0;for(;x;x-=x&-x)cnt=(cnt+tree[id][x])%mod;return cnt;}
int main()
{
	cin>>T;
	for(int u=1;u<=T;u++)
	{
		memset(tree,0,sizeof(tree));
		ans=0;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++)
			scanf("%d",&a[i]),b[i]=a[i];
		sort(b+1,b+n+1);tot=unique(b+1,b+n+1)-b-1;
		for(int i=1;i<=n;i++)
		{
			a[i]=lower_bound(b+1,b+tot+1,a[i])-b;//离散化
			add(1,a[i],1);//初始化
			for(int j=1;j<m;j++)
				add(j+1,a[i],ask(j,a[i]-1));
		}
		ans=ask(m,tot);//答案相当于求f[m]的前缀和,可以直接询问
		printf("Case #%d: %d\n",u,ans);
	}
}

标签:cnt,int,ybtoj,tree,Chibi,add,序列,Battle,leqslant
来源: https://blog.csdn.net/weixin_45523071/article/details/117826015

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有