zoukankan      html  css  js  c++  java
  • [机房测试]上低音号

    Description

    (r imes c) 的矩阵里有 (n) 个点,询问至少包含 (k) 个点的子矩阵有多少个。 (r,c,nleq 3 imes 10^3 , kleq 10)

    Solution

    容易想到一个 (n^3) 的做法。枚举上下边界,中间用 two-pointer 计算贡献。

    但是没有用到 (kleq 10) 这个性质。钦定一个点的贡献为使它成为矩阵最左边的点的合法矩阵个数,考虑对点进行增量更新,容易发现新增一个点只会对按横坐标排序后的往前数的 (k) 个点造成贡献。配合平衡树可以做到 (O(n^2klog n)) 的复杂度。但这样不够优秀。瓶颈在于找下标,所以想到反过来操作,先排序后,用链表维护,然后只需要删除,这样就可以做到 (O(n^2k))。注意边界细节。

    #pragma GCC optimize(2)
    
    #include<stdio.h>
    #include<algorithm>
    #include<vector>
    #include<cassert>
    using namespace std;
    
    typedef long long ll;
    
    inline int read(){
        int x=0,flag=1; char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')flag=0;c=getchar();}
        while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
        return flag? x:-x;
    }
    
    const int N=3e3+7;
    
    struct Node{
        int x,y;
        bool operator <(const Node &X) const{
            return x>X.x;
        }
    }a[N];
    
    vector<int> V[N];
    int head,tail,l[N],r[N];
    
    inline void Ins(int x){
        l[x]=tail,r[tail]=x,tail=x;
    }
    
    int main(){
        freopen("baritone.in","r",stdin);
        freopen("baritone.out","w",stdout);
        int r_=read(),c_=read(),
            n=read(),k=read();
        for(int i=1;i<=n;i++)
            a[i].x=read(),a[i].y=read();
        sort(a+1,a+1+n);
        a[n+1]=(Node){0,0},a[0]=(Node){r_+1,0};
        ll ans=0;
        for(int L=1;L<=c_;L++){
            head=tail=0; int cnt=0;
            for(int i=1;i<=r_;i++) V[i].clear();
            for(int i=1;i<=n;i++)
                if(a[i].y>=L){
                    Ins(i),cnt++;
                    V[a[i].y].push_back(i);
                }
            if(cnt<k) break; Ins(n+1); ll ret=0;
            int p=head; for(int i=1;i<=k;i++) p=r[p];
            for(int i=r[head];p!=tail;i=r[i],p=r[p])
                ret+=1ll*(a[l[i]].x-a[i].x)*a[p].x;
            ans+=ret;
            for(int R=c_;R>L;R--){
                for(int j:V[R]){
                    cnt--;
                    int p=j; for(int i=1;i<k&&l[p]!=head;p=l[p],i++);
                    int o=p; for(int i=1;i<k&&p!=tail;i++,p=r[p]);
                    if(p==tail) continue;
                    for(;p!=tail&&l[o]!=j;p=r[p],o=r[o])
                        ret-=1ll*(a[l[o]].x-a[o].x)*(a[p].x-a[r[p]].x);
                //    if(p!=tail) ret-=1ll*(a[l[o]].x-a[o].x)*a[p].x;
                    r[l[j]]=r[j],l[r[j]]=l[j];
                }
                assert(ret>=0);
                if(cnt<k) break; ans+=ret;
            }
        }
        printf("%lld",ans);
    }
    
  • 相关阅读:
    StopAllSounds
    GotoAndPlay
    区间(interval)
    因数(factor)
    [HAOI2009]逆序对数列
    生物分子gene
    数轴line
    [SCOI2008]配对
    精力(power)
    bzoj4987: Tree(树形dp)
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/15346167.html
Copyright © 2011-2022 走看看