寻找一种有效的算法来回答给定方阵的子矩阵中的查询

时间:2013-12-06 17:52:07

标签: c++ algorithm matrix

我正在尝试解决“Rectangular Queries” problem from the December 2013 CodeChef contest

给定方阵矩阵N x N,用{1,... 10}的整数填充。我们给出Q(10 ^ 5)个查询如下 给定x1,y1,x2,y2找到给定子矩阵中唯一元素的数量。

限制: N <= 300 问(10 ^ 5) x1&lt; = x2&lt; = N. y1&lt; = y2&lt; = N. 时限1秒

我尝试过使用std :: set获取唯一性的方法,但是获得了TLE ...我的方法很天真...从左上角到右下角循环查询并添加元素到set..then printing std :: set.size()。

3 个答案:

答案 0 :(得分:7)

有两种可能的方法: -

  1. 自己解决问题并获得难以获得的积分。

  2. 等待比赛结束并在社论中查看解决方案。

  3. 祝你好运。

答案 1 :(得分:1)

这是一个在时间限制内完成的简单解决方案: -

#include<stdio.h>
#define max 300
int count[max][10][max];
int matrix[max][max];
int N;

void gen_counts() {
 int i,j,k,number,index;

 for(i=0;i<N;i++) {

    for(j=0;j<10;j++)
       count[i][j][0] = 0;
 }

 for(i=0;i<N;i++) {

   for(j=0;j<10;j++) {

    for(k=0;k<N;k++) {
        if(k>0)
           count[i][j][k] = count[i][j][k-1];

        if(matrix[i][k]==j+1) {
             count[i][j][k]++;
        }  

     }

   }

 }


}

int get_distinct(int r1,int c1,int r2,int c2) {
   int i,j,present[10],ret=0;
   for(i=0;i<10;i++)
      present[i] = 0; 
   for(i=r1;i<=r2;i++) {

     for(j=0;j<10;j++) {
        if(c1>0) 
        present[j]=present[j]||(count[i][j][c1-1]<count[i][j][c2]);
        else present[j] = present[j] || (count[i][j][c1]>0||count[i][j][c2]>0);
     }

   }
  for(i=0;i<10;i++)
     ret = ret + present[i];

  return(ret);
}



int main() {

int Q,i,j,r1,r2,c1,c2;

scanf("%d",&N);

for(i=0;i<N;i++) {

 for(j=0;j<N;j++)
   scanf("%d",&matrix[i][j]);
}

gen_counts();

scanf("%d",&Q);

for(i=0;i<Q;i++) {

 scanf("%d%d%d%d",&r1,&c1,&r2,&c2);
 printf("%d\n",get_distinct(r1-1,c1-1,r2-1,c2-1));

}


return(0);

}

答案 2 :(得分:0)

我发现了这个问题的最佳算法......我认为它的复杂性也小于O(n * n)。我认为这将是有用的

#include <stdio.h>

int main(void) {
int n,i,j;
//read matrix dimensions
scanf("%d",&n);

int mat[n][n];
int t,x1,x2,y1,y2;
int counter[10],flag;
//read matrix
for(i=0;i<n;i++){
    for(j=0;j<n;j++){
        scanf("%d",&mat[i][j]);
    }
}

scanf("%d",&t);
//for each test case do this
while(t--){
    scanf("%d%d%d%d",&x1,&y1,&x2,&y2);

    //make all counters zero
    for(i = 0;i<10;i++){
        counter[i]=0;
    }

    flag = 0;

    for(i=x1-1;i<=x2-1;i++){
        for(j=y1-1;j<=y2-1;j++){
            //counter == 0 means we are visiting the element for the first time 
            counter[mat[i][j]-1]++;
        }

    }



    for(i =0;i<10 ;i++){
        if(counter[i]!=0){
            flag++;
        }
    }

    printf("%d\n",flag);

}
return 0;
}