• CF1500D Tiles for Bathroom (递推+大讨论)


    题目大意:给你一个n*n的矩阵,现在问对于每个kle n,求出所有k*k的子矩阵中,元素种类数不超过q的矩阵个数,nle 1500, qle 10

    先考虑最暴力的做法:

    对于每个格子,求出以它为子矩阵右下角时,左上角能到达的最远位置,时间O(n^{4})。再统计起来跑个后缀和

    考虑可以$n^{3}$时的做法:

    双指针对一条斜线上的格子进行维护,暴力进行指针移动时的更新

    虽然双指针是一种优化递推,但其并没有利用q=10的性质

    考虑直接递推

    我们从左到右再从上到下依次处理每个点

    对于每个格子维护一个vector,记录从它开始,不断向左上拓展时,第一次出现某个元素的相对位置信息

    比如

    1 2 3 ...

    1 5 3 ...

    1 2 3 ...

    ...

    现在要处理(3,3)位置上的那个3

    那么它相对于(3,3)的位置就是(3,3),中间的5相对位置是(2,2)。

    5下面的2相对位置也是(2,2),因为如果想在(3,3)把这个2框进去,左上角一定会拓展到(2,2)

    5上面的2相对位置是(1,1),但可惜在记录的时候我们只记录第一次出现的位置

    我们最多只需要记录q+1个元素,第q+1个元素往右下一格就是答案

    当前格子左,上,左上的三个相邻格子都是已知信息,取出来排序,再依次选第一次出现的位置

    但左和上取出来时相对位置可能会改变

    画图发现,这与元素在倒L形的左侧一列/上侧一行的出现情况有关,额外记录元素在这个倒L形左列/上行的出现情况,再进行大讨论即可转移

    直接做会被卡空间,滚动数组就好

      1 int T,n,q; 
      2 int a[N1][N1],sum[N1][N1];
      3 struct node{
      4 int x,y,val; bool tp,le;
      5 };
      6 int cmp(node &s1,node &s2)
      7 {
      8     return s1.x+s1.y>s2.x+s2.y;
      9 }
     10 
     11 int ans[N1];
     12 int now,pst;
     13 vector<node>to[N1][N1];
     14 node se[50];
     15 int tot;
     16 
     17 void addnode(int x,int y,int nx,int ny)
     18 {
     19     int m; node k;
     20     if(x==nx-1&&y==ny-1)
     21     {
     22         m=to[pst][y].size(); 
     23         for(int i=0;i<m;i++)
     24         {
     25             k=to[pst][y][i]; se[tot++]=k;
     26             // se[tot++]=(node){k.x,k.y,k.val,k.tp.k.le};
     27         }
     28     }
     29     if(x==nx-1&&y==ny)
     30     {
     31         m=to[pst][y].size(); 
     32         for(int i=0;i<m;i++)
     33         {
     34             k=to[pst][y][i]; 
     35             if(x==k.x&&y==k.y){
     36                 if(y>1) k.y--; else continue;
     37                 k.le=0; k.tp=1;
     38             }else if(!k.tp){
     39                 k.x++; k.tp=(a[k.x][k.y]==k.val)?1:0; k.le=1;
     40             }else{
     41                 if(k.y>1) k.y--; else continue; // 后续与左侧取并!!
     42                 k.le=(a[k.x][k.y]==k.val)?1:0;
     43             }
     44             se[tot++]=k;
     45         }
     46     }
     47     if(x==nx&&y==ny-1)
     48     {
     49         m=to[now][y].size(); 
     50         for(int i=0;i<m;i++)
     51         {
     52             k=to[now][y][i]; 
     53             if(x==k.x&&y==k.y){
     54                 k.x--;
     55                 k.le=1; k.tp=0;
     56             }else if(!k.le){
     57                 k.y++; k.le=(a[k.x][k.y]==k.val)?1:0; k.tp=1;
     58             }else{
     59                 if(k.x>1) k.x--; else continue; // 后续与上侧取并!!
     60                 k.tp=(a[k.x][k.y]==k.val)?1:0;
     61             }
     62             se[tot++]=k;
     63         }
     64     }
     65 }
     66 void solve(int x,int y)
     67 {
     68     tot=0; se[tot++]=(node){x,y,a[x][y],1,1};
     69     addnode(x-1,y,x,y);
     70     if(y>1) addnode(x-1,y-1,x,y), addnode(x,y-1,x,y);
     71     sort(se,se+tot,cmp); node k; int fl;
     72     for(int i=0;i<tot;i++)
     73     {
     74         k=se[i]; fl=0;
     75         for(int j=0;j<to[now][y].size();j++)
     76         {
     77             if(to[now][y][j].val==k.val)
     78             {
     79                 if(to[now][y][j].x==k.x && to[now][y][j].y==k.y) 
     80                     to[now][y][j].tp|=k.tp, to[now][y][j].le|=k.le;
     81                 fl=1; break; 
     82             }
     83         }
     84         if(!fl)
     85         {
     86             to[now][y].push_back(k);
     87             if(to[now][y].size()==q+1) break;
     88         }
     89     }
     90     int m=to[now][y].size();
     91     // sum[x][y]=x-to[now][y][m-1].x+1;
     92     if(m==q+1) sum[x][y]=x-to[now][y][m-1].x;
     93     else sum[x][y]=min(x,y);
     94 }
     95 
     96 int ret[N1];
     97 int main()
     98 {
     99     // freopen("a.txt","r",stdin);
    100     freopen("a.in","r",stdin);
    101     // srand(time(NULL));
    102     scanf("%d%d",&n,&q);
    103     for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) read(a[i][j]);
    104     now=1, pst=0;
    105     for(int j=1;j<=n;j++)
    106     {
    107         to[0][j].push_back( (node){1,j,a[1][j],1,1} );
    108         sum[1][j]=1;
    109     }
    110     for(int i=2;i<=n;i++)
    111     {
    112         for(int j=1;j<=n;j++)
    113         {
    114             to[now][j].clear();
    115             solve(i,j); 
    116         }
    117         swap(now,pst);
    118     }
    119     for(int i=1;i<=n;i++)
    120     {
    121         for(int j=1;j<=n;j++)
    122         {
    123             ret[1]++; ret[sum[i][j]+1]--;
    124             // printf("%d ",sum[i][j]);
    125         }
    126         // puts("");
    127     }
    128     for(int i=1;i<=n;i++) ret[i]=ret[i-1]+ret[i];
    129     for(int i=1;i<=n;i++) printf("%d
    ",ret[i]);
    130     return 0;
    131 }
  • 相关阅读:
    java数据库编程之DAO模式
    java数据库编程之JDBC
    java数据库编程之初始Mysql
    java数据库编程之常用的操作用户和赋权限
    java数据库编程之事务、视图、索引、备份、恢复
    java数据库编程之嵌套子查询及exists的使用
    .net窗体程序的基础知识及详细笔记
    sql sever 基础知识及详细笔记
    java基础知识及详细笔记
    计算机基础知识及笔记
  • 原文地址:https://www.cnblogs.com/guapisolo/p/14551166.html
Copyright © 2020-2023  润新知