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
看一下上面那个红绿配的图就很明了了~
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端