题目
TUOJ
https://sim.csp.thusaac.com/contest/40/problem/1

思路参考:第40次CSP认证前四题 - Oaths - 博客园
https://www.cnblogs.com/oaths/articles/19327767
核心思路
预处理:根据输入的n,m,k序列,计算出输入为0~511,经过m次g运算后的结果,后面直接查表即可
时间复杂度:O(512*m)
代码
可以再让AI总结一下代码逻辑:
1. 整体功能
-
程序实现了对一个9位二进制数(0-511)经过m次变换后,能够根据变换结果反推出原始输入值
-
使用预处理+查表的方式,避免对每个输入实时计算
2. 核心函数 F(x, m)
-
输入:整数x(0-511)和变换次数m
-
处理流程:
-
将x转换为9位二进制字符串(高位补0)
-
分割成3组3位二进制:s1、s2、s3
-
将每组转换为十进制:a1、b1、c1
-
进行m次迭代运算:
-
a2 = b1
-
b2 = c1 XOR (((b1² + k[i]²) mod 8) XOR k[i])
-
c2 = a1 XOR (((c1² + k[i]²) mod 8) XOR k[i])
-
更新a1、b1、c1
-
-
最终结果 = (a2 << 6) + (b2 << 3) + c2(组合成9位整数)
-
3. 主流程 solve()
-
读取输入:n(查询次数)、m(变换次数)、k数组(变换参数)
-
预处理建表:
-
遍历所有可能的输入值0-511
-
计算每个值经过m次变换后的结果res
-
建立映射:
ans[结果] = 原始输入
-
-
查询输出:
-
对每个查询值a,直接从表中找出对应的原始输入
-
按格式输出结果
-
4. 注意事项
-
位运算优先级:
<<优先级低于+,需要括号 -
输出格式:空格分隔,最后一个数后无空格
cpp
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
const int N=5e5+5, M=1e3+5;
int k[M];
unordered_map<int,int>ans;
//经过m次g运算
int F(int x,int m) //warn:return int
{
string s="";
while(x>0)
{
s+=to_string(x%2);
x/=2;
}
reverse(s.begin(),s.end());
while(s.size()<9) s="0"+s;
string s1=s.substr(0,3);
string s2=s.substr(3,3);
string s3=s.substr(6,3);
int a1=(s1[0]-'0')*4+(s1[1]-'0')*2+(s1[2]-'0');
int b1=(s2[0]-'0')*4+(s2[1]-'0')*2+(s2[2]-'0');
int c1=(s3[0]-'0')*4+(s3[1]-'0')*2+(s3[2]-'0');
int a2=0,b2=0,c2=0;
for(int i=1;i<=m;i++)
{
a2=b1;
b2=c1^(((b1*b1+k[i]*k[i])%8)^k[i]);
c2=a1^(((c1*c1+k[i]*k[i])%8)^k[i]);
a1=a2;
b1=b2;
c1=c2;
}
int ans=(a2<<6)+(b2<<3)+c2; //warn:+的优先级高于<<,所以要()
return ans;
}
void solve()
{
int n,m; cin>>n>>m;
for(int i=1;i<=m;i++) cin>>k[i];
//输入是0到511(2^9)
for(int i=0;i<512;i++) {
int res=F(i,m);
ans[res]=i;
}
for(int i=1;i<=n;i++){
int a; cin>>a;
cout<<ans[a]; //直接查表得到输入
if(i!=n) cout<<" "; //warn:注意输出格式
}
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0);
solve();
return 0;
}