Increasing Speed Limits HDU - 3030 【dp 树状数组 离散化 上升子序列】

Increasing Speed Limite HDU 3030

题意

给你一个长度为m的数组A,你可以通过给的X,Y,Z计算获得一个长度为n的数组,问你这个n长的序列有多少个非空严格上升序列。

思路

dp

  • \(dp[i]\): 以第i个元素为结尾的非空严格上升序列个数
  • \(dp[i] =\sum_{j=1}^{i-1}{dp[j]}+1\), 其中 \(a[j]<a[i]\)
  • \(ans = \sum_{i=1}^n{dp[i]}\)
  • 用树状数组求前缀和

代码

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) (x&(-x));
typedef long long ll;
const int MAXN=500005;
const int MOD= 1000000007;
int n,m;
ll X,Y,Z;
int A[MAXN],a[MAXN],b[MAXN];
ll c[MAXN];
void update(int x,ll value){
	while(x<=n){
		c[x]=(c[x]+value)%MOD;
		x+=lowbit(x);
	}
}
ll getSum(int x){
	ll ret=0;
	while(x){
		ret=(ret+c[x])%MOD;
		x-=lowbit(x);
	}
	return ret;
}
int main(){
//	freopen("in.txt","r",stdin); 
	int T;
	scanf("%d",&T);
	for(int kase=1;kase<=T;kase++){
		scanf("%d%d%lld%lld%lld",&n,&m,&X,&Y,&Z);
		memset(c,0,sizeof(c));
		for(int i=0;i<m;i++)
			scanf("%d",&A[i]);
		for(int i=0;i<n;i++){
			a[i+1]=b[i+1]=A[i%m];
			A[i%m]=(X*A[i%m]+Y*(i+1))%Z;
		}
		sort(a+1,a+n+1);
		int an=unique(a+1,a+n+1)-a-1;
		int p;
		ll ans=0;
		ll tmp=0;
		for(int i=1;i<=n;i++){
			p=lower_bound(a+1,a+an+1,b[i])-a;
			tmp=getSum(p-1)+1;
			ans=(ans+tmp)%MOD;
			update(p,tmp);
		}
		printf("Case #%d: %lld\n",kase,ans);
	}
        return 0;
} 

猜你喜欢

转载自www.cnblogs.com/xuwanwei/p/12806164.html