刷题

0 阅读4分钟

数字变换 (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 个二进制位分为高三位、中三位、低三位三组并将其视为三个数字分别进行变换,具体如下图所示:

img

记 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;
}