其他分享
首页 > 其他分享> > [ybtoj 4.2.3 /UVA12983] The Battle of Chibi

[ybtoj 4.2.3 /UVA12983] The Battle of Chibi

作者:互联网

题意

在一个长度为 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