Pixel Shuffle [Poj 2789,CERC 2005/SWERC 2005,LA 3510]

45 篇文章 0 订阅
3 篇文章 0 订阅

题目地址请点击——


Pixel Shufflent


Description



在一个 n×n n 为偶数) 的黑白位图上反复执行同一个像素混和序列,问重复做几次后会得到原图像?
每个混合序列是由若干个混合命令组成,这些命令如下。

  • id:不变
  • rot:逆时针旋转 90°
  • sym:水平翻转
  • bhsym:下一半的图像水平翻转
  • bvsym:下一半图像垂直翻转
  • div:0,2,4,n2 行变成第 0,1,2,,n/21 行,第 1,3,5,,n1 行变成第 n/2,n/2+1,n1

    • mix:行混合。
      新图像的第 2k 行依次是原图像的
      (2k,0),(2k+1,0),(2k,1),(2k+1,1),,(2k,n21),(2k+1,n21)
      这些像素。
      2k+1 行依次是原图像的
      (2k,n2),(2k+1,n2),(2k,n2+1),(2k+1,n2+1),,(2k,n1),(2k+1,n1)
    • 对字母 A 使用这 7 种混合法后的效果如图所示。

      这里写图片描述


      Input

      第一行为位图边长 n (2n210),第二行为不超过 k k32)个混合命令。
      如果一个命令后面有一个减号“-”,表示应该执行该命令的逆。
      命令从右往左执行。


      Output

      输出最小重复次数。


      Sample Input 1

      256
      rot- div rot div


      Sample Output 1

      8


      Sample Input 2

      256
      bvsym div mix


      Sample Output 2

      63457


      Solution

      每一个操作可视为一个置换,将这些置换的成绩循环分解,然后答案就为所有循环的元素个数的最小公倍数。


      Code

      #include <iostream>
      #include <cstdio>
      #include <cstring>
      
      #define PLA(x,y) PLAS[(x)][(y)]
      
      using namespace std;
      
      char input[100000];
      int T,n,cnt;
      int row[100000];
      int to[1300000];
      bool vis[1300000];
      int PLAS[2000][2000];
      int nxt[1300000];
      
      int gcd(int x,int y){
          return y==0?x:gcd(y,x%y);
      }
      
      void work(int x){
          switch(x){
              case 9:
                  for(int i=0;i<n;i++)
                      for(int j=0;j<n;j++)
                          nxt[PLA(i,j)]=to[PLA(j,n-i-1)];
                  break;
              case 3:
                  for(int i=0;i<n;i++)
                      for(int j=0;j<n;j++)
                          nxt[PLA(i,j)]=to[PLA(i,n-j-1)];
                  break;
              case 4:
                  for(int i=0;i<n;i++)
                      for(int j=0;j<n;j++)
                          if(i>=n/2)nxt[PLA(i,j)]=to[PLA(i,n-j-1)];
                  break;
              case 5:
                  for(int i=0;i<n;i++)
                      for(int j=0;j<n;j++)
                          if(i>=n/2)nxt[PLA(i,j)]=to[PLA(n/2+n-1-i,j)];
                  break;
              case 7:
                  for(int i=0;i<n;i++)
                      for(int j=0;j<n;j++){
                          if(!((i)&1))nxt[PLA(i,j)]=to[PLA(i+((j)&1),(j)/2)];
                          else nxt[PLA(i,j)]=to[PLA(i+((j)&1)-1,(j)/2+n/2)];
                      }
                  break;
              case 2:
                  for(int i=0;i<n;i++)
                      for(int j=0;j<n;j++)
                          nxt[PLA(i,j)]=to[PLA(n-j-1,i)];
                  break;
              case 6:
                  for(int i=0;i<n;i++)
                      for(int j=0;j<n;j++)
                          if(i<n/2)nxt[PLA(i,j)]=to[PLA((i)*2,j)];
                          else nxt[PLA(i,j)]=to[PLA(2*(i-n/2)+1,j)];
                  break;
              case 13:
                  for(int i=0;i<n;i++)
                      for(int j=0;j<n;j++)
                          if(!((i)&1))nxt[PLA(i,j)]=to[PLA(i/2,j)];
                          else nxt[PLA(i,j)]=to[PLA(i/2+n/2,j)];
                  break;
              case 14:
                  for(int i=0;i<n;i++)
                      for(int j=0;j<n;j++){
                          if(j<n/2){
                              if(!((i)&1))nxt[PLA(i,j)]=to[PLA(i,(j)*2)];
                              else nxt[PLA(i,j)]=to[PLA(i-1,(j)*2+1)];
                          }
                          else{
                              if(!((i)&1))nxt[PLA(i,j)]=to[PLA(i+1,(j-n/2)*2)];
                              else nxt[PLA(i,j)]=to[PLA(i,(j-n/2)*2+1)];
                          }
                      }
                  break;
              default:break;
          }
          for(int i=0;i<n;i++)
              for(int j=0;j<n;j++)
                  to[PLA(i,j)]=nxt[PLA(i,j)];
      }
      
      int main(){
      
          scanf("%d",&n);gets(input);if((input[0]<'a'||input[0]>'z')&&(input[0]<'A'||input[0]>'Z'))gets(input);
      
          for(int i=0;i<n;i++)
              for(int j=0;j<n;j++)PLAS[i][j]=((i)*n+(j)+1);
      
          int l=strlen(input);cnt=0;
      
          int end=PLA(n-1,n-1);
          for(int i=1;i<=end;i++)to[i]=nxt[i]=i;
      
          for(int i=0;i<=l;i++){
              if(input[i]==' '||i==l){
                  switch(input[i-1]){
                      case 'd':continue;
                      case 't':row[++cnt]=2;break;
                      case 'v':row[++cnt]=6;break;
                      case 'x':row[++cnt]=7;break;
                      case 'm':
                          if(i>3&&input[i-4]=='h')row[++cnt]=4;
                          else if(i>3&&input[i-4]=='v')row[++cnt]=5;
                          else row[++cnt]=3;
                          break;
                      case '-':
                          switch(input[i-2]){
                              case 'd':continue;
                              case 't':row[++cnt]=9;break;
                              case 'v':row[++cnt]=13;break;
                              case 'x':row[++cnt]=14;break;
                              case 'm':
                                  if(i>4&&input[i-5]=='h')row[++cnt]=4;
                                  else if(i>4&&input[i-5]=='v')row[++cnt]=5;
                                  else row[++cnt]=3;
                                  break;
                              default:break;
                          }
                          break;
                      default:break;
                  }
              }
          }
      
          for(int i=cnt;i>=1;i--)work(row[i]);
      
          int ans=1;
          for(int i=1;i<=end;i++)if(!vis[i]){
              int j=i,tot=0;
              do{
                  vis[j]=true;
                  tot++;
                  j=to[j];
              }while(i!=j);   
              ans=ans/gcd(ans,tot)*tot;
          }
          printf("%d",ans);
      
          return 0;
      }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值