开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第8天,点击查看活动详情.
1. 题目介绍(ezcrypto)
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]);
}
}
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;
}