Nowcoder Summer Trainning 6 TF
Nowcoder Summer Trainning 6 TF
题意
定义一棵树的Hash如下:
\[H = (\sum_{i=1}^{n-1}\sum_{j=i+1}^{n}X^iY^jZ^{lca(i,j)})mod\ P(P=998244353)
\]
给定F(T)、X、Y和Z,构造一棵树的Hash值为F(T).
题解
构造方案如下:
取37个点,每个点的父节点先设置为1,这样可以计算出一个Hash值为H0.
下面做调整,将后36个点分为6组,每组可以选择一个点z作为父节点,选取另外两个点x,y,将这两个点的父节点设置为z,这样有\((6*C(5,2))^6=90^6\)种方案,每种方案对答案有影响为del。而由于X、Y、Z都是随机生成的,相当于随机了\(90^6\)个调整方案,在本题数域范围[0, P]内与我们答案F(T)碰撞概率极大。
这样问题转化为了:在6组,每组90个数中取一个数,使他们和为F(T)-H0.
采用meet in middle减少枚举量。
分成前三组和后三组,枚举前三组之和记录到map里,再枚举后三组之和在map中寻找碰撞。
代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define endl '\n'
const int MAXN = 0;
const double eps = 1e-6;
const LL MOD = 998244353;
LL FT, X, Y, Z;
LL H0 = 0;
LL fast_pow(LL a, LL b)
{
LL res = 1;
while (b)
{
if (b & 1)
res = res * a % MOD;
b >>= 1;
a = a * a % MOD;
}
return res;
}
struct node
{
LL x1, y1, z1, x2, y2, z2, x3, y3, z3;
};
map<LL, node> mp;
node ans1, ans2;
void solve()
{
mp.clear();
H0 = 0;
cin >> FT >> X >> Y >> Z;
for (int i = 1; i <= 36; ++i)
for (int j = i + 1; j <= 37; ++j)
H0 = (H0 + fast_pow(X, i) * fast_pow(Y, j) % MOD * Z % MOD) % MOD;
for (int z1 = 2; z1 <= 7; ++z1)
for (int x1 = 2; x1 <= 6; ++x1)
if (x1 != z1)
for (int y1 = x1 + 1; y1 <= 7; ++y1)
if (y1 != z1)
for (int z2 = 2; z2 <= 7; ++z2)
for (int x2 = 2; x2 <= 6; ++x2)
if (x2 != z2)
for (int y2 = x2 + 1; y2 <= 7; ++y2)
if (y2 != z2)
for (int z3 = 2; z3 <= 7; ++z3)
for (int x3 = 2; x3 <= 6; ++x3)
if (x3 != z3)
for (int y3 = x3 + 1; y3 <= 7; ++y3)
if (y3 != z3)
{
LL del = fast_pow(X, x1) * fast_pow(Y, y1) % MOD * (fast_pow(Z, z1) - Z) % MOD;
del += fast_pow(X, x2 + 6) * fast_pow(Y, y2 + 6) % MOD * (fast_pow(Z, z2 + 6) - Z) % MOD;
del += fast_pow(X, x3 + 12) * fast_pow(Y, y3 + 12) % MOD * (fast_pow(Z, z3 + 12) - Z) % MOD;
if (z1 < x1)
del += fast_pow(X, z1) * fast_pow(Y, x1) % MOD * (fast_pow(Z, z1) - Z) % MOD;
else
del += fast_pow(X, x1) * fast_pow(Y, z1) % MOD * (fast_pow(Z, z1) - Z) % MOD;
if (z2 < x2)
del += fast_pow(X, z2 + 6) * fast_pow(Y, x2 + 6) % MOD * (fast_pow(Z, z2 + 6) - Z) % MOD;
else
del += fast_pow(X, x2 + 6) * fast_pow(Y, z2 + 6) % MOD * (fast_pow(Z, z2 + 6) - Z) % MOD;
if (z3 < x3)
del += fast_pow(X, z3 + 12) * fast_pow(Y, x3 + 12) % MOD * (fast_pow(Z, z3 + 12) - Z) % MOD;
else
del += fast_pow(X, x3 + 12) * fast_pow(Y, z3 + 12) % MOD * (fast_pow(Z, z3 + 12) - Z) % MOD;
if (z1 < y1)
del += fast_pow(X, z1) * fast_pow(Y, y1) % MOD * (fast_pow(Z, z1) - Z) % MOD;
else
del += fast_pow(X, y1) * fast_pow(Y, z1) % MOD * (fast_pow(Z, z1) - Z) % MOD;
if (z2 < y2)
del += fast_pow(X, z2 + 6) * fast_pow(Y, y2 + 6) % MOD * (fast_pow(Z, z2 + 6) - Z) % MOD;
else
del += fast_pow(X, y2 + 6) * fast_pow(Y, z2 + 6) % MOD * (fast_pow(Z, z2 + 6) - Z) % MOD;
if (z3 < y3)
del += fast_pow(X, z3 + 12) * fast_pow(Y, y3 + 12) % MOD * (fast_pow(Z, z3 + 12) - Z) % MOD;
else
del += fast_pow(X, y3 + 12) * fast_pow(Y, z3 + 12) % MOD * (fast_pow(Z, z3 + 12) - Z) % MOD;
del = ((del % MOD) + MOD) % MOD;
mp[del] = (node){x1, y1, z1, x2 + 6, y2 + 6, z2 + 6, x3 + 12, y3 + 12, z3 + 12};
}
for (int z1 = 2; z1 <= 7; ++z1)
for (int x1 = 2; x1 <= 6; ++x1)
if (x1 != z1)
for (int y1 = x1 + 1; y1 <= 7; ++y1)
if (y1 != z1)
for (int z2 = 2; z2 <= 7; ++z2)
for (int x2 = 2; x2 <= 6; ++x2)
if (x2 != z2)
for (int y2 = x2 + 1; y2 <= 7; ++y2)
if (y2 != z2)
for (int z3 = 2; z3 <= 7; ++z3)
for (int x3 = 2; x3 <= 6; ++x3)
if (x3 != z3)
for (int y3 = x3 + 1; y3 <= 7; ++y3)
if (y3 != z3)
{
LL del = fast_pow(X, x1 + 18) * fast_pow(Y, y1 + 18) % MOD * (fast_pow(Z, z1 + 18) - Z) % MOD;
del += fast_pow(X, x2 + 24) * fast_pow(Y, y2 + 24) % MOD * (fast_pow(Z, z2 + 24) - Z) % MOD;
del += fast_pow(X, x3 + 30) * fast_pow(Y, y3 + 30) % MOD * (fast_pow(Z, z3 + 30) - Z) % MOD;
if (z1 < x1)
del += fast_pow(X, z1 + 18) * fast_pow(Y, x1 + 18) % MOD * (fast_pow(Z, z1 + 18) - Z) % MOD;
else
del += fast_pow(X, x1 + 18) * fast_pow(Y, z1 + 18) % MOD * (fast_pow(Z, z1 + 18) - Z) % MOD;
if (z2 < x2)
del += fast_pow(X, z2 + 24) * fast_pow(Y, x2 + 24) % MOD * (fast_pow(Z, z2 + 24) - Z) % MOD;
else
del += fast_pow(X, x2 + 24) * fast_pow(Y, z2 + 24) % MOD * (fast_pow(Z, z2 + 24) - Z) % MOD;
if (z3 < x3)
del += fast_pow(X, z3 + 30) * fast_pow(Y, x3 + 30) % MOD * (fast_pow(Z, z3 + 30) - Z) % MOD;
else
del += fast_pow(X, x3 + 30) * fast_pow(Y, z3 + 30) % MOD * (fast_pow(Z, z3 + 30) - Z) % MOD;
if (z1 < y1)
del += fast_pow(X, z1 + 18) * fast_pow(Y, y1 + 18) % MOD * (fast_pow(Z, z1 + 18) - Z) % MOD;
else
del += fast_pow(X, y1 + 18) * fast_pow(Y, z1 + 18) % MOD * (fast_pow(Z, z1 + 18) - Z) % MOD;
if (z2 < y2)
del += fast_pow(X, z2 + 24) * fast_pow(Y, y2 + 24) % MOD * (fast_pow(Z, z2 + 24) - Z) % MOD;
else
del += fast_pow(X, y2 + 24) * fast_pow(Y, z2 + 24) % MOD * (fast_pow(Z, z2 + 24) - Z) % MOD;
if (z3 < y3)
del += fast_pow(X, z3 + 30) * fast_pow(Y, y3 + 30) % MOD * (fast_pow(Z, z3 + 30) - Z) % MOD;
else
del += fast_pow(X, y3 + 30) * fast_pow(Y, z3 + 30) % MOD * (fast_pow(Z, z3 + 30) - Z) % MOD;
del = ((del % MOD) + MOD) % MOD;
del = (FT - H0 - del + MOD + MOD) % MOD;
if (mp.count(del))
{
ans1 = mp[del];
ans2 = (node){x1 + 18, y1 + 18, z1 + 18, x2 + 24, y2 + 24, z2 + 24, x3 + 30, y3 + 30, z3 + 30};
return;
}
}
}
int main()
{
ios::sync_with_stdio(false);
cout.tie(NULL);
int T = 1;
cin >> T;
while (T--)
{
solve();
cout << 37 << '\n';
for (int i = 2; i <= 37; ++i)
if (i != ans1.x1 && i != ans1.x2 && i != ans1.x3 && i != ans1.y1 && i != ans1.y2 && i != ans1.y3
&& i != ans2.x1 && i != ans2.x2 && i != ans2.x3 && i != ans2.y1 && i != ans2.y2 && i != ans2.y3)
cout << 1 << ' ' << i << '\n';
cout << ans1.z1 << ' ' << ans1.x1 << '\n';
cout << ans1.z1 << ' ' << ans1.y1 << '\n';
cout << ans1.z2 << ' ' << ans1.x2 << '\n';
cout << ans1.z2 << ' ' << ans1.y2 << '\n';
cout << ans1.z3 << ' ' << ans1.x3 << '\n';
cout << ans1.z3 << ' ' << ans1.y3 << '\n';
cout << ans2.z1 << ' ' << ans2.x1 << '\n';
cout << ans2.z1 << ' ' << ans2.y1 << '\n';
cout << ans2.z2 << ' ' << ans2.x2 << '\n';
cout << ans2.z2 << ' ' << ans2.y2 << '\n';
cout << ans2.z3 << ' ' << ans2.x3 << '\n';
cout << ans2.z3 << ' ' << ans2.y3 << '\n';
}
return 0;
}