1. 程式人生 > >Petya and Array CodeForces - 1042D

Petya and Array CodeForces - 1042D

ios 個數 arr clas tdi 有一個 size begin 如果

很不錯的一道題

給你一個長度為n的數組,問共有多少個區間滿足區間之和小於給定的數t

這種題一般做法肯定是枚舉,固定左端點枚舉右端點,枚舉的過程需要優化,否則就是n方

這道題我先求一個前綴和,然後逆著枚舉,顯然問題轉化為了對於一個數,如果尋找他右邊的數哪些小於它+t,這就轉化為了區間求和,可以樹狀數組或者線段樹,但是數的範圍太大,因此需要用離散化

這道題的還有一個問題是定位,有一個很簡單的定位方法就是把每一個前綴和+t也放進去,這樣去定位就很簡單了

另外就是使用upper_bound不過找的數要減一

具體做法看代碼

#include<bits/stdc++.h>
using namespace
std; #define endl "\n" #define pf printf #define int long long #define IO ios::sync_with_stdio(0);cin.tie(0);cout.tie(0) const int maxn=200000+5; int sum[maxn],a[maxn],up; vector<int> v; int n,t; inline int lowbit(int x){return x&-x;} void add(int x,int d) { while(x<=up){ sum[x]+=d;x+=lowbit(x); } }
int Sum(int x) { int ret=0; while(x>0){ ret+=sum[x]; x-=lowbit(x); } return ret; } main() { IO; int ans=0; cin>>n>>t; for(int i=1;i<=n;i++){ cin>>a[i]; a[i]+=a[i-1]; v.push_back(a[i]); if(a[i]<t) ans++; } sort(v.begin(),v.end()); v.erase(unique(v.begin(),v.end()),v.end()); up
=v.size(); for(int i=n;i;i--){ ans+=Sum(upper_bound(v.begin(),v.end(),a[i]+t-1)-v.begin()); add(lower_bound(v.begin(),v.end(),a[i])-v.begin()+1,1); } cout<<ans<<endl; }

Petya and Array CodeForces - 1042D