• 【CF627E】Orchestra(链表)


    点此看题面

    大致题意: 给定一个(r imes c)的矩阵,其中有(n)(1)。问有多少子矩阵包含至少(k)(1)

    解题思路

    不得不说这题的思想是非常巧妙的。

    有一个显而易见的(O(r^2c))暴力,即枚举子矩阵上下边界,然后用尺取法(双指针)扫一遍。

    现在我们考虑仍旧枚举上边界,然后从下往上枚举下边界,每次移动下边界时求出删去这一层点给答案带来的变化。

    删去一个点,因此而减少的贡献就是所有包含它所在列且恰好包含(k)个点的矩阵个数。

    我们用链表来维护有点的每一列,那么暴力找出这些矩阵最多也就只要往前跳(k)次,同时维护好右边界即可。

    总复杂度(O(r^2k))

    (P.S.) 写完后发现似乎也可以从上往下枚举下边界,然后加上每一层点的答案?而且这样还不用求初始答案了。。。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 3000
    #define K 10
    #define LL long long
    using namespace std;
    int r,c,n,k,cnt[N+5],pre[N+5],nxt[N+5],C[N+5],v[N+5][N+5];struct P {int x,y;}p[N+5];
    int main()
    {
    	RI i,j,s,x,y;for(cin>>r>>c>>n>>k,i=1;i<=n;++i) cin>>x>>y,v[x][++C[x]]=y;//记下每一行的点的列号
    	RI t,cur,res;LL ans=0;for(i=1;i<=r;++i)//枚举上边界
    	{
    		for(res=0,j=i;j<=r;++j) for(s=1;s<=C[j];++s) ++cnt[v[j][s]];//枚举所有点计算每一列的点数
    		for(pre[1]=0,j=2;j<=c+1;++j) pre[j]=cnt[j-1]?j-1:pre[j-1];//链表初始化向前指针
    		for(nxt[c]=c+1,j=c-1;~j;--j) nxt[j]=cnt[j+1]?j+1:nxt[j+1];//链表初始化向后指针
    		for(x=nxt[0];x<=c;x=nxt[x])//枚举子矩阵第一个有1的列,计算初始答案
    		{
    			t=0,y=x;W(y<=c&&(t+=cnt[y])<k) y=nxt[y];//暴力向后跳到第一个满足条件的右边界
    			res+=(x-pre[x])*(c-y+1);//统计答案
    		}
    		for(j=r;j>=i;--j) for(ans+=res,s=1;s<=C[j];++s)//从下往上枚举下边界,删去每层点的贡献
    		{
    			if(--cnt[cur=v[j][s]]>=k) continue;//如果这一列的点数仍旧大于等于k,对答案无影响
    			t=0,y=cur;W(y<=c&&(t+=cnt[y])<k-1) y=nxt[y];//暴力向后跳找到初始右边界
    			x=cur;W(x)//枚举左边界
    			{
    				W(y^cur&&t-cnt[y]>=k-1) t-=cnt[y],y=pre[y];if(y==cur&&t>=k) break;//右边界能移就移,若不合法就结束循环
    				t+1==k&&(res-=(x-pre[x])*(nxt[y]-y)),t+=cnt[x=pre[x]];//恰好k个点时从答案中减去贡献,然后移动左边界
    			}
    			!cnt[cur]&&(nxt[pre[cur]]=nxt[cur],pre[nxt[cur]]=pre[cur]);//没点后从链表中删去
    		}
    	}return printf("%lld
    ",ans),0;//输出答案
    }
    
  • 相关阅读:
    4.14打印特殊图案
    4.13十进制/二进制转换器
    4.12程序运行时间
    4.11 计算文件的大小
    4.10文件的读写
    4.9位运算
    CyclicBarrier
    tar 命令
    MySQL 常用函数介绍
    mysql 表转 java 实体 sql
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF627E.html
Copyright © 2020-2023  润新知