题解 (by;zjvarphi)
先提出来所有偶数的 (2),那么所有的偶数就会变成一段从 (1) 开始的前缀和,继续递归下去计算.
问题转化成求 (Pi_{i=1}^{(n-1)/2}(2i+1))。
将括号拆开,最多选 63 个 2,再多就会因为自然溢出而没有作用。
所以这里可以化为:从 (n) 个数里选 (m) 个数的所有方案数的乘积和。
设 (g_{n,m}) 表示从 (n) 个数中选 (m) 个,所有方案数的乘积总和,这样式子可以转化为:(sum_{i=0}^{63}g_{n,i}*2^i)。
求 (g) 时可以递推:(g_{n,m}=n imes g_{n-1,m-1}+g_{n-1,m})。
转化一下,(g) 表示没选的数的乘积:(g_{n,m}=g_{n-1,m-1}+n imes g_{n-1,m})。
发现给 (n) 加 (1) 后就变成了第一类斯特林数 (n+1 rack n-m+1)。
这个数很大,但是发现 (n-m+1) 很小,所以圆排列中大于 (1) 的环很少。
预处理出 (dp_{i,j}) 表示 (i) 个数分成 (j) 个圆排列,每个圆排列至少大于 (1) 的方案数。
最后就是如何求逆元,发现偶数无法求逆元,所以将偶数除去所有 (2) 的因子,剩下的奇数利用欧拉定理求出即可。
Code
#include<bits/stdc++.h>
#define ri signed
#define pd(i) ++i
#define bq(i) --i
#define func(x) std::function<x>
namespace IO{
char buf[1<<21],*p1=buf,*p2=buf;
#define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?(-1):*p1++
#define debug1(x) std::cerr << #x"=" << x << ' '
#define debug2(x) std::cerr << #x"=" << x << std::endl
#define Debug(x) assert(x)
struct nanfeng_stream{
template<typename T>inline nanfeng_stream &operator>>(T &x) {
bool f=false;x=0;char ch=gc();
while(!isdigit(ch)) f|=ch=='-',ch=gc();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=gc();
return x=f?-x:x,*this;
}
}cin;
}
using IO::cin;
namespace nanfeng{
#define FI FILE *IN
#define FO FILE *OUT
template<typename T>inline T cmax(T x,T y) {return x>y?x:y;}
template<typename T>inline T cmin(T x,T y) {return x>y?y:x;}
using ull=unsigned long long;
static const int N=155;
int T;
ull A[N][N],dp[N][N],inv[N];
auto fpow=[](ull x,ull y) {
ull res=1ull;
while(y) {
if (y&1) res=res*x;
x=x*x;
y>>=1;
}
return res;
};
auto C=[](ull n,int m) {
ull res=1ull;
int cnt=0;
for (ri i(1);i<=m;pd(i)) {
res*=inv[i];
int k=i;
while(!(k&1)) k>>=1,++cnt;
}
for (ull i(n-m+1);i<=n;pd(i)) {
ull k=i;
while(cnt&&!(k&1)) k>>=1,--cnt;
res*=k;
}
return res;
};
auto calc=[](ull x) {
--x;
x>>=1;
ull res=0;
++x;
for (ri t(0);t<64&&t<x;pd(t)) {
ull tmp=0;
for (ri k(t);k<=t<<1&&k<=x;pd(k)) tmp+=C(x,k)*dp[k][k-t];
res+=tmp<<t;
}
return res;
};
inline int main() {
FI=freopen("multiplication.in","r",stdin);
FO=freopen("multiplication.out","w",stdout);
for (ri i(0);i<=N-5;pd(i)) {
A[i][0]=1ull;
for (ri j(1);j<=i;pd(j)) A[i][j]=A[i][j-1]*(i-j+1);
}
dp[0][0]=1ull;
for (ri i(1);i<=N-5;pd(i))
for (ri j(1);j<=i;pd(j))
for (ri k(2);k<=i;pd(k)) dp[i][j]+=A[i-1][k-1]*dp[i-k][j-1];
for (ri i(1);i<=150;pd(i)) {
ull x=i;
while(!(x&1)) x>>=1;
inv[i]=fpow(x,(1ull<<63)-1ull);
}
cin >> T;
for (ri i(1);i<=T;pd(i)) {
ull x,c=0,ans=1ull;
cin >> x;
while(x) ans*=calc(x),x>>=1,c+=x;
ans<<=(c%4);
bool jud=false;
for (ri t(15);~t;bq(t)) {
ull tmp=ans>>(t*4)&15;
if (tmp) jud=true;
if (jud) putchar(tmp<10?tmp+'0':tmp-10+'A');
}
printf("
");
}
return 0;
}
}
int main() {return nanfeng::main();}