数字变换 (transform)
时间限制: 1.5 秒
空间限制: 512 MiB
相关文件: 题目目录
题目描述
小 C 设计了一种变换 FF,若输入 [0,29)[0,29) 中的整数,则输出也是 [0,29)[0,29) 中的整数。
记 ⊕⊕ 为按位异或运算,即 C++/Java/Python 中的 ^ 运算符。
若 x,kx,k 均为 [0,23)[0,23) 内的整数,定义 f(x,k)=((x2+k2)mod23)⊕kf(x,k)=((x2+k2)mod23)⊕k。
若 xx 为 [0,29)[0,29) 内的整数,kk 为 [0,23)[0,23) 内的整数。将 xx 的二进制表示进行高位补零的操作,使其恰好为 99 位。g(x,k)g(x,k) 将会把这 99 个二进制位分为高三位、中三位、低三位三组并将其视为三个数字分别进行变换,具体如下图所示:
记 f0f0 为 FF 变换的输入值,并定义 fi=g(fi−1,ki)fi=g(fi−1,ki),i∈1,2,3,⋯,mi∈1,2,3,⋯,m,则 fmfm 为 FF 变换的输出值。长为 mm 的序列 kk 是一个给定的参数序列,并且其中每个数字都是 [0,23)[0,23) 之间的整数。
现在小 C 有 nn 个经过 FF 变换后得到的值,分别为 a1,a2,⋯,ana1,a2,⋯,an,小 C 想知道它们对应的输入分别是什么。
输入格式
从标准输入读入数据。
第一行两个正整数 n,mn,m。
第二行有 mm 个非负整数,分别为 k1,k2,⋯,kmk1,k2,⋯,km。
第三行有 nn 个非负整数,分别为 a1,a2,⋯,ana1,a2,⋯,an。
输出格式
输出到标准输出。
输出一行 nn 个非负整数,表示 a1,a2,⋯,ana1,a2,⋯,an 对应的输入。
样例1输入
1 2
3 5
504
样例1输出
101
样例1解释
可以枚举可能的输入并验证。
若枚举到的输入为 f0=101f0=101。
对于 f1=g(101,3)f1=g(101,3) 来说:a=1a=1,b=4b=4,c=5c=5,c⊕f(b,3)=7c⊕f(b,3)=7,a⊕f(c,3)=0a⊕f(c,3)=0,故 f1=312f1=312。
对于 f2=g(312,5)f2=g(312,5) 来说:a=4a=4,b=7b=7,c=0c=0,c⊕f(b,5)=7c⊕f(b,5)=7,a⊕f(c,5)=0a⊕f(c,5)=0,故 f2=504f2=504。
因此若输入为 101101,则输出为 504504,因此 101101 是其对应的输入。
如果枚举的输入是别的数字,可以同上验证其输出不是 504504。
子任务
80%80% 的测试数据满足:1≤n≤1001≤n≤100,1≤m≤201≤m≤20。
100%100% 的测试数据满足:1≤n≤5×1051≤n≤5×105,1≤m≤1031≤m≤103,0≤ki<230≤ki<23,0≤ai<2n9,且只有唯一的输入能够得到这些输出。
题目分析
题目中有意列举手段引导,第一印象是我能不能一一列举,但是感觉很吃力不讨好。
再想一想题目说0<n<512,且只有唯一的输入能够得到这些输出。我们可以事先将所有情况算出来,再进行查表,以空间换时间。
#include<iostream>
#include<vector>
using namespace std;
int f(int x,int k){
return ((x*x+k*k)%8)^k;
}
int g(int x,int k){
int c=x&7;
int b=(x>>3)&7;
int a=(x>>6)&7;
int next_c=a^f(c,k);
int next_b=c^f(b,k);
int next_a=b;
return (next_a<<6)|(next_b<<3)|next_c;
}
int main(){
ios:: sync_with_stdio(false);
cin.tie(nullptr);
int n,m;
if(!(cin>>n>>m))return 0;
vector<int>K(m);
for(int i=0;i<m;i++)cin>>K[i];
int rev_map[512]={0};
for(int i=0;i<512;i++){
int current=i;
for(int j=0;j<m;j++){
current=g(current,K[j]);
}
rev_map[current]=i;
}
for(int i=0;i<n;i++){
int a;
cin>>a;
cout<<rev_map[a]<<(i==n-1?"":" ");
}
cout<<"\n";
return 0;
}
优点: 1.位运算简洁优美,值得学习
int g(int x,int k){
int c=x&7;
int b=(x>>3)&7;
int a=(x>>6)&7;
int next_c=a^f(c,k);
int next_b=c^f(b,k);
int next_a=b;
return (next_a<<6)|(next_b<<3)|next_c;
}