C. Tokitsukaze and Strange Inequality_字首和dp+特殊列舉
阿新 • • 發佈:2022-05-09
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
看一下上面那個紅綠配的圖就很明瞭了~