C. Tokitsukaze and Strange Inequality_前缀和dp+特殊枚举

C. Tokitsukaze and Strange Inequality

题目大意

给一个数列,找四个下标[a,b,c,d],满足a<b<c<d。找出满足以下条件的种数。
a_a<a_c && a_b>a_d

思路和代码

我一开始做了一个O(n3 logn)的方法,有点笨。

具体就是枚举ac和b再二分d。

void solve(){//错误代码!!!
	int n ;
	cin >> n ;
	vct<int> a(n + 1 , 0) ;
	
	rep(i , 1 , n) cin >> a[i] ;
	
	vct<vct<int> > grt(n + 1) ;//i后面比ai大的
	vct<vct<int> > sml(n + 1) ;//i后面比ai小的
	
	rep(i , 1 , n)
	rep(j , i + 1 , n){
		if(a[j] > a[i]) grt[i].pb(j) ;
		else sml[i].pb(j) ;
	}
	
	ll ans = 0 ;
	
	rep(i , 1 , n){
		
		for(int j : grt[i]){
			
			rep(u , i + 1 , j - 1){
				int id = upper_bound(sml[u].begin() , sml[u].end() , j) - sml[u].begin() + 1 ;
				ans += sml[u].size() - id + 1 ;
			}
			
		}
		
	}
	cout << ans << "\n" ;
}//错误代码!!!

这样做的复杂度很高。所以换一种方法。

将题目转化为【1,b】中比a[c]小的乘上【c,n】中比a[c]小的。于是我们就可以去枚举b和c

void solve3(){
	int n ;
	cin >> n ;
	vct<ll> a(n + 1 , 0) ;
	rep(i , 1 , n) cin >> a[i] ;
	
	vct<vct<int> > lft(n + 1 , vct<int> (n + 1 , 0)) ;
	vct<vct<int> > rit(n + 1 , vct<int> (n + 1 , 0)) ;
	
	rep(i , 1 , n){
		ll num = 0 ;
		rep(jl , 1 , i - 1){//[1,jl]中比ai小的 
			num += a[jl] < a[i] ;
			lft[i][jl] = 1LL * num ;
		}
		
		num = 0 ;
		rep(jr , i + 1 , n){//[i+1,jr]中比ai小的 
			num += a[i] > a[jr] ;
			rit[i][jr] = 1LL * num ;
		}
	}
	
	ll ans = 0 ;
	
	rep(i , 1 , n)
	rep(j , i + 1 , n){
		ans += 1LL * (rit[i][n] - rit[i][j]) * (lft[j][i - 1]) ;
        //([i+1,n]中比ai小的 - [i+1,j]中比ai小的)* [1,i-1]中比aj小的
	}
	cout << ans << "\n" ;
	
}

当然以上代码不太好理解点就是其rit和lft的定义不太一致。具体看代码注释。

小结

结合dp思想,枚举中间点转化问题。

这是一个很好的题目

Update2022/5/9

昨晚打完比赛有点神志不清了,随便写了点就下机,现在来补充一些...

题目就是要求出下图的四元点对数量

考虑枚举中间点b和c。构造前(后)缀和dp数组lft和rit 。

1)rit[i,j]表示在[j,n]范围内比ai小的数量

2)rit[i,j]表示在[j,n]范围内比ai小的数量

所以最后的答案就是lft[c,b-1]*rit[b,c+1]在n2枚举b和c时求和。

void solve(){
	cin >> n ;
	vct<int> a(n + 1 , 0) ;
	
	get1(a , 1 , n) ;
	vct<vct<int> > lft(n + 2 , vct<int>(n + 2 , 0)) ;
	vct<vct<int> > rit(n + 2 , vct<int>(n + 2 , 0)) ;
	
	rep(i , 1 , n)
	rep(j , 1 , i - 1){
		lft[i][j] = lft[i][j - 1] + (a[i] > a[j] ? 1 : 0) ;
	}//lft[i,j]表示[1,j]中比ai小的数量 
	
	rep(i , 1 , n)
	drep(j , i + 1 , n){
		rit[i][j] = rit[i][j + 1] + (a[i] > a[j] ? 1 : 0) ;
	}//rit[i,j]表示[j,n]中比ai小的数量 

	ll ans = 0 ;
	rep(i , 1 , n - 1)
	rep(j , i + 1 , n)
	ans += 1LL * lft[j][i - 1] * rit[i][j + 1] ;
	
	cout << ans << "\n" ;
	
}//code_by_tyrii 

看一下上面那个红绿配的图就很明了了~

posted @   tyrii  阅读(117)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示