Codeforces Round #208 E. Dima and Kicks

                                                                       E. Dima and Kicks
                                                             time limit per test 2 seconds
                                                             memory limit per test   256 megabytes
input
standard input
output
standard output

Dima is a good person. In fact, he's great. But all good things come to an end...

Seryozha is going to kick Dima just few times.. For this reason he divides the room into unit squares. Now the room is a rectanglen × m consisting of unit squares.

For the beginning, Seryozha put Dima in a center of some square. Then he started to kick Dima (it is known, that he kicks Dima at least once). Each time when Dima is kicked he flyes up and moves into one of four directions (up, left, right, down). On each move Dima passes k(k > 1) unit of the length in the corresponding direction. Seryozha is really kind, so he kicks Dima in such way that Dima never meets the walls (in other words, Dima never leave the room's space). Seryozha is also dynamic character so Dima never flies above the same segment, connecting a pair of adjacent squares, twice.

Seryozha kicks Dima for a long time, but Dima is not vindictive — Dima writes. Dima marked all squares in which he was staying or above which he was flying. Thanks to kicks, Dima does not remember thek value, so he asks you to find all possible values which matches to the Dima's records.

Input

The first line contains n andm (1 ≤ n, m ≤ 103) — size of the room.

Next n lines goes, each containsm numbers aij — Dima's notes:aij = 1, if Dima was staying in the square(i, j) or was flying above it. Otherwiseaij = 0.

At least one aij equals1.

Output

In a single line in accending order print all k (k > 1), which matches the Dima's notes. If there are no suchk and Dima invented this story with kicks, print -1.


看了别人的代码,思路至今仍未捋清。

在2和Min(n,m)之间枚举k值,遍历矩阵,多条件检测k值。(以后再详解。。。)

#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <set>
#include <string>
#include <math.h>
#define N 1010
using namespace std;
int n,m,tot;
int a[N][N];
int s0[N][N],s1[N][N],d[N][N];
int readInt(){        //输入挂
  char c;
  int n=0;
  c=getchar();
  while(c<'0'||c>'9') c=getchar();
  while(c>='0'&&c<='9'){
    n=n*10+c-'0';
    c=getchar();                      
  }    
  return n;
}
int fa[N*N];
int sx,sy;   //默认初始化为0
int ok(int x,int y){
  return x>=1&&x<=n&&y>=1&&y<=m ;    
}
int find(int i)      //并查集
{
  if(fa[i]==i)  return i;
  else  return find(fa[i]);   
}
int can(int k){
    int i,j,x,y,mx,my,tmp;
    int dd=0,fmx;
    fmx=(sx-1)/k,mx=(n-sx)/k,my=(m-sy)/k,dd=0;   //mx,my记录距离下墙、右墙的kick数
    for(i=-fmx;i<=mx;i++)
      for(j=0;j<=my;j++){
         d[i+fmx][j]=0;
         int num=(i+fmx)*(my+1)+j;
         fa[num]=num;
      }
    for(i=-fmx;i<=mx;i++){
      for(j=0;j<=my;j++){
        x=sx+i*k;     //所能到达的位置
        y=sy+j*k;                   
        if(!a[x][y])  continue;
        dd++;
        if(ok(x+k,y)&&a[x+k][y]){   //向下走
          tmp=s0[x+k-1][y]-s0[x][y];
          if(tmp==k-1){
            d[i+fmx][j]++;
            d[i+1+fmx][j]++;
            dd+=k-1;
            fa[find((i+fmx)*(my+1)+j)]=fa[find((i+1+fmx)*(my+1)+j)];             
          }    
          else if(tmp>0)  return 0;                   
        }
        if(ok(x,y+k)&&a[x][y+k]){  //向右走
          tmp=s1[x][y+k-1]-s1[x][y];
          if(tmp==k-1){
            d[i+fmx][j]++;
            d[i+fmx][j+1]++;
            dd+=k-1;
            fa[find((i+fmx)*(my+1)+j)]=fa[find((i+fmx)*(my+1)+j+1)];             
          }    
          else if(tmp>0)  return 0;                          
        }        
      }                      
    }
    if(dd!=tot)  return 0;        //所经过的单元总数
    int cnt=0,thef=find((0+fmx)*(my+1)+0);
    for(i=-fmx;i<=mx;i++)
      for(j=0;j<=my;j++){
        cnt+=d[i+fmx][j]&1;                   
      }
    for(i=-fmx;i<=mx;i++)
      for(j=0;j<=my;j++){
        x=sx+i*k;
        y=sy+j*k;
        if(!a[x][y])  continue;
        if(find((i+fmx)*(my+1)+j)!=thef)   return 0;
      }
    return cnt<=2;
}
int main()
{
  int i,j,k;
  while(scanf("%d %d",&n,&m)!=EOF){
    tot=0;
    for(i=1;i<=n;i++)
      for(j=1;j<=m;j++){  
        //scanf("%d",&a[i][j]);
        a[i][j]=readInt();
        tot+=a[i][j];         //通过的总单元数            
      }
    if((n<3&&m<3)|| tot==1){
       printf("-1\n");             
    }
    else{
     for(i=1;i<=n;i++)
       for(j=1;j<=m;j++){  
        s0[i][j]=s0[i-1][j]+a[i][j];
        s1[i][j]=s1[i][j-1]+a[i][j];            
       }
     sx=sy=0;
     for(j=1;j<=m;j++){      //纵向搜索第一个不为0的单元位置
       for(i=1;i<=n;i++){
        if(a[i][j]){
          sx=i;sy=j; break;             
        }                  
       }                  
       if(sx) break;
     }
     int flag=1;
     for(k=2;k<=min(n,m);k++){
           //printf("can(%d)=%d\n",k,can(k));
           if(can(k)){
             if(flag)  flag=0;
             else   printf(" ");
             printf("%d",k);         
           }                                                            
     }
     if(flag)  printf("-1\n");
     else printf("\n");
    }         
  }
  return 0;
}


 

转载于:https://www.cnblogs.com/james1207/p/3395247.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值