2 条题解

  • 5
    @ 2024-7-29 19:38:51

    一道恶心的大模拟,一定要分步做

    1、枚举“有效区域”

    题目要求是四个顶点字母恰好和原始数字表的四个顶点数字互相对应,即 num1,1num_{1,1}alphabetx,yalphabet_{x,y} 对应、num1,nnum_{1,n}alphabetx,y+n1alphabet_{x,y+n-1} 对应、numn,1num_{n,1}alphabetx+n1,yalphabet_{x+n-1,y} 对应、numn,nnum_{n,n}alphabetx+n1,y+n1alphabet_{x+n-1,y+n-1} 对应

    2、记录每次解密

    每次找到一个“有效区域”,我们就要统计它四角的大写字母个数,以便后面的旋转

    3、顺时针旋转

    这个式子要自己推理,代码如下:

    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            turn[i][j]=s[n-j+1][i];
    

    4、进行“数字关联”

    考虑建立01数组,对于 numnum 数组,若 numi,jnum_{i,j}∈ { 0,2,3,5,70,2,3,5,7 } ,则标记为 11,反之同理(注意特判 numi,j=1num_{i,j}=1 的情况);若 alphabeti,jalphabet_{i,j} 为大写字母,则标记为 11,反之同理,若 numi,jnum_{i,j} 的标记等于 alphabeti,jalphabet_{i,j} 的标记,或者 numi,j=0num_{i,j}=0,则数字关联成功,给答案字符串加上这个字符

    实现以上功能后输出即可。

    屎山展示:

    #include<bits/stdc++.h>
    using namespace std;
    int n,m,s[305][305],cun[305][305],a[305][305],dx[305][305],turn[305][305];
    char num[305][305],alp[305][305];
    string ans="";
    int check(int u){
    	return int(u==2||u==3||u==5||u==7);
    }
    int main(){
    	cin>>n>>m;
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=n;j++){
    			cin>>num[i][j];
    			s[i][j]=int(num[i][j]-'0');
    			cun[i][j]=s[i][j];
    		} 
    	}
    	for(int i=1;i<=m;i++){
    		for(int j=1;j<=m;j++){
    			cin>>alp[i][j];
    			if(alp[i][j]>='a'&&alp[i][j]<='z') a[i][j]=int(alp[i][j]-'a')+1,dx[i][j]=0;
    			else a[i][j]=int(alp[i][j]-'A')+1,dx[i][j]=1;
    		} 
    	}
    	for(int i=1;i<=m-n+1;i++){
    		for(int j=1;j<=m-n+1;j++){
    			int cnt=0;
    			if(a[i][j]==s[1][1]&&a[i+n-1][j]==s[n][1]&&s[1][n]==a[i][j+n-1]&&s[n][n]==a[i+n-1][j+n-1]){
    				if(alp[i][j]<'a') cnt++;
    				if(alp[i+n-1][j]<'a') cnt++; 
    				if(alp[i][j+n-1]<'a') cnt++;
    				if(alp[i+n-1][j+n-1]<'a') cnt++;
    				for(int x=i;x<=i+n-1;x++)
    					for(int y=j;y<=j+n-1;y++)
    						if((check(s[x-i+1][y-j+1])==dx[x][y]&&s[x-i+1][y-j+1]!=1)||s[x-i+1][y-j+1]==0) ans+=alp[x][y];
    				for(int p=1;p<=cnt;p++){
    					for(int x=1;x<=n;x++)
    					    for(int y=1;y<=n;y++)
    					        turn[x][y]=s[n-y+1][x];
    					for(int x=1;x<=n;x++)
    					    for(int y=1;y<=n;y++)
    					        s[x][y]=turn[x][y];
    					for(int x=i;x<=i+n-1;x++)
    					    for(int y=j;y<=j+n-1;y++)
    						    if((check(s[x-i+1][y-j+1])==dx[x][y]&&s[x-i+1][y-j+1]!=1)||s[x-i+1][y-j+1]==0) ans+=alp[x][y];
    				}
    				for(int x=1;x<=n;x++)
    				    for(int y=1;y<=n;y++)
    				        s[x][y]=cun[x][y];
    			}
    		}
    	}
    	if(ans=="") cout<<"No solution";
    	else cout<<ans;
    }
    
    • 3
      @ 2024-8-1 15:40:26

      虽然非常牛波一的申哥已经发了一次题解,但是他的代码都是挤在main函数里,可能导致有的同学理解起来有些困难,特此水一发自己的

      Ps:因为没看清题卡了好久

      #include<bits/stdc++.h> 
      using namespace std;
      
      typedef long long ll;
      const ll N = 3e2 + 10;
      
      ll n, m, num[N][N], dui[N][N], tmp[N][N], res[N][N];
      char code[N][N];
      string ans;
      
      bool isPrime(ll x){             // 判断是否为质数
          if (x == 2 || x == 3 || x == 5 || x == 7) return true;
          return false;
      }
      
      bool isUpper(char x){           // 判断是否大写
          return (x >= 'A' && x <= 'Z');
      }
      
      bool isCorre(ll x, ll y){       // 判断该区域是否有效,x和 y是字母表中要枚举的矩阵的开始下标
          ll x2 = x + n - 1, y2 = y + n - 1;
      
          if (num[1][1] == dui[x][y] && num[1][n] == dui[x][y2] && num[n][1] == dui[x2][y] && num[n][n] == dui[x2][y2]) return true;
          return false;
      }
      
      void turnRight(ll cnt){         // 把数字表旋转,cnt是要转几次
          while (cnt --){
              for (ll i = 1; i <= n; i ++)
                  for (ll j = 1; j <= n; j ++)
                      tmp[i][j] = num[n - j + 1][i];
              
              for (ll i = 1; i <= n; i ++)
                  for (ll j = 1; j <= n; j ++)
                      num[i][j] = tmp[i][j];
          }
      }
      
      ll countUpper(ll x, ll y){      // 统计 4个角的大写字母数量
          ll x2 = x + n - 1, y2 = y + n - 1;
      
          return ((isUpper(code[x][y])) + (isUpper(code[x][y2])) + (isUpper(code[x2][y])) + (isUpper(code[x2][y2])));
      }
      
      void decode(ll x, ll y){       // 解密,转换成密码
          string tmpans;
      
          for (ll i = x; i <= x + n - 1; i ++){
              for (ll j = y; j <= y + n - 1; j ++){
                  if ((isPrime(num[i - x + 1][j - y + 1]) == isUpper(code[i][j])) && num[i - x + 1][j - y + 1] != 1 || (!num[i - x + 1][j - y + 1])) tmpans += code[i][j];
                  else continue;
              }
          }
      
          ans += tmpans;
      }
      
      void restore(){                 // 转完后,把数字表还原
          for (ll i = 1; i <= n; i ++)
              for (ll j = 1; j <= n; j ++) num[i][j] = res[i][j];
      
          return;
      }
      
      int main(){
          ios::sync_with_stdio(0), cout.tie(0), cin.tie(0);
      
          cin >> n >> m;
      
          // 输入数字表
          for (ll i = 1; i <= n; i ++) 
              for (ll j = 1; j <= n; j ++){
                  char x;
                  cin >> x;
                  num[i][j] = x - '0', res[i][j] = num[i][j];
              }
      
          // 输入字母表
          for (ll i = 1; i <= m; i ++) 
              for (ll j = 1; j <= m; j ++){
                  cin >> code[i][j];
                  if (code[i][j] >= 'A' && code[i][j] <= 'Z') dui[i][j] = code[i][j] - 'A' + 1;
                  else dui[i][j] = code[i][j] - 'a' + 1;
              }
      
          // 枚举有效区域
          for (ll i = 1; i <= m - n + 1; i ++)    
              for (ll j = 1; j <= m - n + 1; j ++){
                  if (isCorre(i, j)){
                      ll uppercnt = countUpper(i, j);
                      do{         // 根据题目要求解密
                          decode(i, j);
                          turnRight(1);
                      }while (uppercnt --);
      
                      restore();  // 解密完后把数字表回去
                  }
              }
      
      
          // 输出答案
          if (!ans.size()) cout << "No solution";
          else cout << ans << endl;
      
          return 0;
      }
      

      结合注释可以更好地理解一下,Goodbye. Goodbye.

      • @ 2024-8-1 18:59:14

        你是不知道呀,前天孙涛给你改H1040的代码改得哭爹喊娘的,跟王老师抱怨了一下午

      • @ 2024-8-1 21:27:03

        他说2点之前给我改完,但是4点才好()只能说孙涛辛苦力(

      • @ 2024-9-15 12:10:05

        怎么用不了啊???

    • 1

    信息

    ID
    768
    时间
    1000ms
    内存
    256MiB
    难度
    8
    标签
    递交数
    70
    已通过
    13
    上传者