I. Latitude Compressor 题解 - 2022 Hubei Provincial Collegiate Programming Contest
赛时基本对了,结果被我推的错误数值表 hack 了队友,并且由于对多项式的操作不熟,导致最后一步一直没想出来
【大意】
给定 ,求集合
其中 表示 对应的置换
【分析】
根据群论的基础知识,排列对应的置换可以拆解为若干个轮换,每个轮换又刚好对应到不同的环上
设某个环大小为 ,则在置换 次后,其会分解为 个环,并且每个环有 个元素
我们不妨考虑这 个元素在 次置换后构成了哪些环:
我们令 表示这 个元素在 次置换后,是否恰好含有 个 元环的逻辑值(可以有其他非 元环)
那么,设 个元素构成的环大小分别为 ,则 即为是否存在一组 满足 都有 且
队友是说,对于每个 ,求出 ,那么就有
考虑 个不同元素构成 元环的方案数,为
因此,在 次置换后, 个元素恰好构成 个 元环的 EGF 即为
故任意多的 元环的 EGF 为
因此,总的 EGF 为
故答案为
我们考虑令 ,则答案为
因此
令 ,则
因此对于每个 ,求解其具体数值的复杂度为 ;求解 的复杂度为 ;再因此累加到 上,复杂度为
因此,总复杂度为
最后只需要 由 进行多项式 exp 求解出 得到答案
而求解 需要的 ,需要先预处理 的所有因子,数量级为
之后,再对每一个 ,枚举 的因子求解 的 最小值,复杂度即为
因此,总复杂度为
【代码】
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define fi first
#define sz(a) (int)a.size()
#define de(x) cout << #x <<" = "<<x<<endl
#define dd(x) cout << #x <<" = "<<x<<" "
#define all(x) x.begin(), x.end()
#define pw(x) (1ll<<(x))
#define lc(x) ((x)<<1)
#define rc(x) ((x)<<1|1)
#define rsz(a, x) (a.resize(x))
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef double db;
const int P=998244353;
const int LimBit=18;
const int M=1<<LimBit<<1;
const int MAXN=5e4+10;
inline int kpow(int a, int x, int p=P) { int ans=1; for(;x;x>>=1, a=(ll)a*a%p) if(x&1) ans=(ll)ans*a%p; return ans; }
inline int exgcd(int a, int b, int &x, int &y) {
static int g;
return b?(exgcd(b, a%b, y, x), y-=a/b*x, g):(x=1, y=0, g=a);
}
inline int inv(int a, int p=P) {
static int x, y;
return exgcd(a, p, x, y)==1?(x<0?x+p:x):(-1);
}
namespace Poly {
const int G=3;
struct vir {
int v;
vir(int v_=0):v(v_>=P?v_-P:v_) {
}
inline vir operator + (const vir &x) const { return vir(v+x.v); }
inline vir operator - (const vir &x) const { return vir(v+P-x.v); }
inline vir operator * (const vir &x) const { return vir((ll)v*x.v%P); }
inline vir operator - () const { return vir(P-v); }
inline vir operator ! () const { return vir(inv(v)); }
inline operator int() const { return v; }
};
struct poly : public vector<vir> {
inline friend ostream& operator << (ostream& out, const poly &p) {
if(!p.empty()) out<<(int)p[0];
for(int i=1; i<sz(p); ++i) out<<" "<<(int)p[i];
return out;
}
};
int N, N_, Stk[M], curStk, rev[M];
vir invN, Inv[M], w[2][M];
inline void init() {
N_=-1;
curStk=0;
Inv[1]=1;
for(int i=2; i<M; ++i)
Inv[i]=-vir(P/i)*Inv[P%i];
}
inline void work() {
if(N_==N) return ;
N_=N;
int d=__builtin_ctz(N);
vir x(kpow(G, (P-1)/N)), y=!x;
w[0][0]=w[1][0]=1;
for(int i=1; i<N; ++i) {
rev[i]=(rev[i>>1]>>1)|((i&1)<<d-1);
w[0][i]=x*w[0][i-1], w[1][i]=y*w[1][i-1];
}
invN=!vir(N);
}
inline void FFT(vir a[M], int f) {
static auto make = [=](vir w, vir &a, vir &b) { w=w*a; a=b-w; b=b+w; };
for(int i=0; i<N; ++i) if(i<rev[i]) swap(a[i], a[rev[i]]);
for(int i=1; i<N; i<<=1)
for(int j=0, t=N/(i<<1); j<N; j+=i<<1)
for(int k=0, l=0; k<i; ++k, l+=t)
make(w[f][l], a[j+k+i], a[j+k]);
if(f) for(int i=0; i<N; ++i) a[i]=a[i]*invN;
}
vir p1[M], p0[M];
inline void get_mul(poly &a, poly &b, int na, int nb) {
for(N=1; N<na+nb-1; N<<=1);
for(int i=0; i<na; ++i) p1[i]=(int)a[i]; for(int i=na; i<N; ++i) p1[i]=0;
for(int i=0; i<nb; ++i) p0[i]=(int)b[i]; for(int i=nb; i<N; ++i) p0[i]=0;
work(); FFT(p1, 0); FFT(p0, 0);
for(int i=0; i<N; ++i) p1[i]=p1[i]*p0[i];
FFT(p1, 1);
rsz(a, na+nb-1); for(int i=0; i<sz(a); ++i) a[i]=p1[i];
}
poly a, b;
inline void get_inv(poly &f, poly &g, int n) {
int pos=curStk;
for(int i=n; i>1; i=i+1>>1) Stk[++curStk]=i;
rsz(g, 1); g[0]=!f[0];
b=f; rsz(b, n);
for(int l=Stk[curStk]; curStk>pos; l=Stk[--curStk]) {
get_mul(a=g, g, l+1>>1, l+1>>1); rsz(a, l);
get_mul(a, b, l, l);
rsz(g, l);
for(int i=0; i<l; ++i) g[i]=g[i]+g[i]-a[i];
}
}
inline void get_der(poly &f, poly &g) {
rsz(g, sz(f));
for(int i=0; i<sz(f)-1; ++i) g[i]=f[i+1]*vir(i+1);
rsz(g, sz(f)-1);
}
inline void get_int(poly &f, poly &g, int C=0) {
rsz(g, sz(f)+1);
for(int i=sz(f); i; --i) g[i]=f[i-1]*Inv[i]; g[0]=C;
}
inline void get_ln(poly &f, poly &g, int n, int ln0=0) {
get_inv(f, g, n);
get_der(f, a); rsz(a, n);
get_mul(g, a, n, n); rsz(g, n);
get_int(g, g, ln0); rsz(g, n);
}
poly c;
inline void get_exp(poly &f, poly &g, int n, int exp0=1) {
int pos=curStk;
for(int i=n; i>1; i=i+1>>1) Stk[++curStk]=i;
rsz(g, 1); g[0]=exp0;
for(int l=Stk[curStk]; curStk>pos; l=Stk[--curStk]) {
get_ln(g, c, l);
for(int i=0; i<l; ++i) c[i]=f[i]-c[i];
c[0]=c[0]+vir(1);
get_mul(g, c, l+1>>1, l); rsz(g, l);
}
}
}
using Poly::poly;
using Poly::vir;
poly a, b, c;
vector<int> divv;
int n, m;
int mind[MAXN];
vir fact[MAXN], inft[MAXN];
int fxy(int x, int y) { return y%mind[x]==0; }
inline void work() {
fact[0]=1;
for(int i=1; i<=n; ++i) fact[i]=vir(i)*fact[i-1];
inft[n]=!fact[n];
for(int i=n; i>=1; --i) inft[i-1]=vir(i)*inft[i];
rsz(a, n+1);
for(int i=1, x; i<=n; ++i) {
x=n/i;
rsz(b, x+1);
vir tmp=1, r=!vir(i);
for(int j=0; j<=x; ++j, tmp=tmp*r)
if(fxy(i, j))
b[j]=inft[j]*tmp;
else
b[j]=0;
Poly::get_ln(b, c, x+1);
for(int j=0, k=0; j<=x; ++j, k+=i)
a[k]=a[k]+c[j];
}
Poly::get_exp(a, b, n+1);
vir x=fact[n]*b[n];
cout<<(int)x;
}
inline int solve(int x) {
for(auto d : divv)
if(__gcd(x, d)==1)
return m/d;
}
inline void divit(int m) {
for(int i=1; i*i<=m; ++i) if(m%i==0) {
divv.push_back(i);
if(i!=m/i) divv.push_back(m/i);
}
sort(divv.begin(), divv.end());
reverse(divv.begin(), divv.end());
}
inline void init() {
Poly::init();
cin>>n>>m;
divit(m);
for(int x=1; x<=n; ++x)
mind[x]=solve(x);
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
init();
work();
cout.flush();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
2021-07-10 题解 poj 2154 Color
2021-07-10 poj 1286 Necklace of Beads 题解