【秋季热身赛】No.1. ezcrypto -- Java Version

63 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第8天,点击查看活动详情.

1. 题目介绍(ezcrypto)

problem1 problem2

2. 题解

该题主要考察的就是对已加密数字的解密,解密的方法就是将加密的过程反向即可。但是Java中由于没有unsigned int,所以样例输入得到的输出结果一直不对,这里我就在Java Solution中加入了加密的实现过程,然后再解密,通过这样的方式即可得到正确结果。

2.1 Java Version

/**
 * Java Template
**/
import java.util.Scanner;

class Main {
    private static int m[] = new int[21];
    private static int c[] = new int[21];
    private static char s[] = new char[21];
    private static int n;
    private static long k;

    public static void encrypto() {
        int delta = 114514;
        int T = 32;
        int sum = 0;
        int v0 = m[n - 1], v1;
        while (T != 0) {
            T--;
            sum += delta;
            for (int i = 0; i < n - 1; i++) {
                v1 = m[i + 1];
                m[i] = m[i] + ((v0 << 4) ^ (v1 >>> 4) ^ sum);
                v0 = m[i];
            }
            m[n - 1] = m[n - 1] + ((v0 << 4) ^ (m[0] >>> 4) ^ sum);
            v0 = m[n - 1];
        }
    }

    public static void decrypto() {
        int delta = 114514;
        int T = 32;
        int sum = ; //sum倒过来计算应该是之前累加的delta
        int v0 = c[n - 2], v1; //v0是当前要加密的数组的上一位,v1是下一位
        while (T != 0) {
            T--;
            c[n - 1] -= (v0 << 4) ^ (c[0] >>> 4) ^ sum;
            for (int i = n - 2; i >= 1; i--) {
                v1 =;//v0是当前要加密的数组的上一位,v1是下一位
                v0 =;
                c[i] -= (v0 << 4) ^ (v1 >>> 4) ^ sum;
            }
            c[0] -=;
            v0 = c[n - 2];//更新v0
            sum -= delta;//sum经过一轮减一次delta
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();
        long k;
        for (int i = 0; i < n; i++) {
            k = scanner.nextLong();
            m[i] = (int) k;
        }
        for (int i = 0; i < n; i++) c[i] = m[i];
        decrypto();
        for (int i = 0; i < n; i++) System.out.print((char) c[i]);

    }
}

加密流程:从m[1]开始到m[n-2]为止,这一部分都属于 它本身<<4 和 下一位>>4的情况,m[0]的时候,由于v[0]初始化,所以是最后一位m[n-1]<<4 和 下一位>>4的情况;而m[n-1]由于没有下一位,这里让m[0]作为了m[n-1]的下一位,形成闭环,所以它属于最后一位的前一位m[n-2]<<4 和 m[0]>>4的情况。解密流程只需要将加的依次减去即可。

/**
* Java Solution
**/
import java.util.Scanner;
// 1414964137 -1482038842 -1161189835 193701658 -68325252 -845416118 1972080655
class Main {
   private static int m[] = new int[21];
   private static int c[] = new int[21];
   private static char s[] = new char[21];
   private static int n;
   private static long k;

   public static void encrypto() {
       int delta = 114514;
       int T = 32;
       int sum = 0;
       // vo代表最后一个元素
       int v0 = m[n - 1], v1;
       // 32次循环准备
       while (T != 0) {
           T--;
           sum += delta;
           // 遍历数组元素 g:47 1000111 o:48 0011 0000 b:66 01000010
           for (int i = 0; i < n - 1; i++) {
               // v1代表下一个元素
               v1 = m[i + 1];
               // g: 47 + (528 ^
               m[i] = m[i] + ((v0 << 4) ^ (v1 >> 4) ^ sum);
               v0 = m[i];
           }
           // 尾元素由于没有下一个元素,故单独计算 v0 = n-2
           m[n - 1] = m[n - 1] + ((v0 << 4) ^ (m[0] >> 4) ^ sum);
           v0 = m[n - 1];
       }
   }

    public static void decrypto() {
        int delta = 114514;
        int T = 32;
        int sum = 3664448; //sum倒过来计算应该是之前累加的delta
        int v0 = c[n - 2], v1; //v0是当前要加密的数组的上一位,v1是下一位
        while (T != 0) {
            T--;
            c[n - 1] -= (v0 << 4) ^ (c[0] >> 4) ^ sum;
            for (int i = n - 2; i >= 1; i--) {
                v1 = c[i+1];//v0是当前要加密的数组的上一位,v1是下一位
                v0 = c[i-1];
                c[i] -= (v0 << 4) ^ (v1 >> 4) ^ sum;
            }
            c[0] -= (c[n-1] << 4) ^ (c[1] >> 4) ^ sum;
            v0 = c[n - 2];//更新v0
            sum -= delta;//sum经过一轮减一次delta
        }
    }

   public static void main(String[] args) {
       Scanner scanner = new Scanner(System.in);
       //n = scanner.nextInt();
       String res = scanner.nextLine();
       n = res.length();
       s = res.toCharArray();

       for (int i = 0; i < n; i++) {
           m[i] = (int) s[i];
           System.out.println((int) s[i]);
       }
       encrypto();
       for (int i = 0; i < n; i++) System.out.print((int) m[i] + " ");
       
       for (int i = 0; i < n; i++) c[i] = m[i];
       decrypto();

       for (int i = 0; i < n; i++) System.out.print((char) c[i]);
   }
}

act1

2.2 C Version

/**
 * C Solution
**/

#include<bits/stdc++.h>
#define ll long long
using namespace std;
char s[21];
unsigned int m[21],c[21],n;

void decrypto(){
    unsigned int delta=114514;
    unsigned int T=32;
    unsigned int sum= 3664448; //sum倒过来计算应该是之前累加的delta
    unsigned int v0=c[n-2],v1; //v0是当前要加密的数组的上一位,v1是下一位
    while(T--){
        c[n-1]-=(v0<<4)^(c[0]>>4)^sum;// c[n-1]的上一位是c[n-2],下一位是c[0],看作一个环
        for(unsigned int i=n-2;i>=1;i--){
            v1= c[i+1];//v0是当前要加密的数组的上一位,v1是下一位
            v0= c[i-1];
            c[i]-=(v0<<4)^(v1>>4)^sum;
        }
        c[0]-= (c[n-1] << 4) ^ (c[1] >> 4) ^ sum;;//c[0]也单独处理上一位跟下一位同c[n-1]
        v0=c[n-2];//更新v0
        sum-=delta;//sum经过一轮减一次delta
    }
}

int main (){
    cin>>n;
    for(int i=0;i<n;i++)cin>>m[i];
    for(unsigned int i=0;i<n;i++)c[i]=m[i];
    decrypto();
    for(unsigned int i=0;i<n;i++)
        cout<<(char)c[i];
    return 0;
}

act2