这个题其实挺好的(除了条件没给清)
题解
最显然的dp,f[i]表示在i打了一枪最多得到多少只鸟,$f[i]=sumlimits_{j=1}^{j<=i-k}f[j]+cnt[i]$然而如果一只鸟长度跨越几次开枪一只鸟会被重复算很多次,比如1秒开次枪,鸟100000长度,会多算
所以实际dp应该是$f[i]=sumlimits_{j=1}^{j<=i-k} f[j]+cnt[i]-chongfu$,
可以利用差分思想,假设一只鸟覆盖[l,r],在鸟来之前[l,r]-1鸟走之后[l,r]+1,每多算一次[l,r]区间的鸟,也会被多减一次1,最后统一给[l,r]+1就得到了实际的值!
用线段树维护区间+,-,区间max,set维护每只鸟即可
代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; #define ll long long #define A 2001101 struct tree{ ll l,r,maxx,f; }tr[A]; struct node{ ll l,r; node(){} node(const ll &a,const ll &b){ l=a,r=b; } friend bool operator < (const node &a,const node &b){ return a.r<b.r; } }qujian[A]; ll cmp(const node &a,const node &b){ return a.l<b.l; } multiset<node> st; multiset<node> :: iterator it; ll maxx,tot,k,n,mx,ans; ll cnt[A],in[A],f[A]; void built(ll x,ll l,ll r){ tr[x].l=l,tr[x].r=r; if(l==r){ return ; } ll mid=(tr[x].l+tr[x].r)>>1; built(x<<1,l,mid); built(x<<1|1,mid+1,r); } void up(ll x){ tr[x].maxx=max(tr[x<<1].maxx,tr[x<<1|1].maxx); } void down(ll x){ tr[x<<1].maxx+=tr[x].f; tr[x<<1|1].maxx+=tr[x].f; tr[x<<1].f+=tr[x].f; tr[x<<1|1].f+=tr[x].f; tr[x].f=0; } void seg_add(ll x,ll l,ll r,ll d){ // printf("l=%lld r=%lld tr[x].l=%lld .r=%lld ",l,r,tr[x].l,tr[x].r); if(tr[x].l>=l&&tr[x].r<=r){ tr[x].maxx+=d; tr[x].f+=d; return ; } if(tr[x].f) down(x); ll mid=(tr[x].l+tr[x].r)>>1; if(mid>=l) seg_add(x<<1,l,r,d); if(mid<r) seg_add(x<<1|1,l,r,d); up(x); } void seg_max(ll x,ll l,ll r){ if(l>r) return ; // printf("tr[x].l=%lld r=%lld l=%lld r=%lld ",tr[x].l,tr[x].r,l,r); if(tr[x].l>=l&&tr[x].r<=r){ maxx=max(maxx,tr[x].maxx); return ; } if(tr[x].f) down(x); ll mid=(tr[x].l+tr[x].r)>>1; if(mid>=l) seg_max(x<<1,l,r); if(mid<r) seg_max(x<<1|1,l,r); up(x); } void insert(ll x,ll pla,ll val){ // printf("***l=%lld r=%lld pla=%lld val=%lld ",tr[x].l,tr[x].r,pla,val); if(tr[x].l==tr[x].r){ tr[x].maxx+=val; return ; } if(tr[x].f) down(x); ll mid=(tr[x].l+tr[x].r)>>1; if(mid>=pla) insert(x<<1,pla,val); else insert(x<<1|1,pla,val); up(x); } void print(ll x){ printf("l=%lld r=%lld f=%lld maxx=%lld ",tr[x].l,tr[x].r,tr[x].f,tr[x].maxx); if(tr[x].l==tr[x].r) return ; print(x<<1),print(x<<1|1); } int main(){ // freopen("da.in","r",stdin); // freopen("ans.sol","w",stdout); scanf("%lld%lld",&n,&k); for(ll i=1;i<=n;i++){ ll l,r; scanf("%lld%lld",&l,&r); if(r<0) continue ; l=max(0ll,l); qujian[++tot]=node(l,r); mx=max(mx,r); cnt[l]++,cnt[r+1]--; in[l]++; } for(ll i=1;i<=mx;i++) cnt[i]+=cnt[i-1]; built(1,0,mx); sort(qujian+1,qujian+tot+1,cmp); ll ita=1,now=0; for(ll i=0;i<=mx;i++){ // printf("i=%lld ",i); while(qujian[ita].l==i){ st.insert(qujian[ita]); ita++;now++; } maxx=0; seg_max(1,0,i-k); maxx+=cnt[i]; ans=max(ans,maxx); // printf("***maxn=%lld ",maxx); insert(1,i,maxx-now); it=st.lower_bound(node(0,0)); while(it!=st.end()&&it->r<=i){ ll l=it->l,r=it->r; node tmp=*it; seg_add(1,l,r,1); it++; now--; st.erase(tmp); } // print(1); } printf("%lld ",ans); }