「解题报告」AHOI2022 排列
这个标题格式我才看出来它的优越性,如果用「AHOI2022 排列 题解」这种写法会感觉「AHOI2022」「排列」「题解」是并列地位的,比较奇怪,我目前就想到这一种解决方案,也就是 APJ 的那种标题格式 .
首先 当且仅当 在同一个置换环中 .
然后 就是 所有置换环长度的 lcm,交换 相当于合并两个置换环,可以手玩一下看出来 .
对于环长 满足关系 ,于是本质不同的 只有 种,可以暴力枚举两种 .
首先处理初始答案,然后每次合并 对 分解质因数然后重新计算贡献即可 .
时间复杂度 .
const int N = 5e5 + 123, P = 1e9 + 7;
int n, p[N], inv[N], cc[N];
bool nsp[N], vis[N];
vector<pii> fac[N];
multiset<int> cycc[N];
vector<int> prime, cyc;
inline void init(int n)
{
inv[1] = 1;
for (int i=2; i<=n; i++) inv[i] = 1ll * (P - P/i) * inv[P % i] % P;
for (int i=2; i<=n; i++)
{
if (nsp[i]) continue;
prime.emplace_back(i);
for (int j=i; j<=n; j+=i){nsp[j] = true; fac[j].emplace_back(make_pair(i, i));}
for (int j=i; j<=n/i; j*=i)
for (int k=j*i; k<=n; k+=j*i){fac[k].pop_back(); fac[k].emplace_back(make_pair(i, j * i));}
}
}
int main()
{
int T; scanf("%d", &T); init(5e5);
while (T--)
{
scanf("%d", &n); int ans = 0, all = 1; cyc.clear(); cyc.emplace_back(-1);
for (int x : prime)
{
if (x > n) break;
cycc[x].clear();
}
for (int i=1; i<=n; i++){vis[i] = false; cc[i] = 0;} //
for (int i=1; i<=n; i++) scanf("%d", p+i);
for (int i=1; i<=n; i++)
if (!vis[i])
{
int cycle = 0;
for (int j=i; !vis[j]; j=p[j]){++cycle; vis[j] = true;}
++cc[cycle];
}
for (int i=1; i<=n; i++)
if (cc[i])
{
cyc.emplace_back(i);
for (int _=1; _<=cc[i]; _++)
for (pii e : fac[i]) cycc[e.first].insert(e.second);
}
for (int x : prime)
{
if (x > n) break;
cycc[x].insert(1);
}
for (int x : prime)
{
if (x > n) break;
all = 1ll * all * *cycc[x].rbegin() % P;
}
int m = cyc.size() - 1;
for (int i=1; i<=m; i++)
for (int j=i; j<=m; j++)
{
if ((i == j) && (cc[cyc[i]] == 1)) continue;
int now = all, val;
if (i == j) val = 1ll * cc[cyc[i]] * (cc[cyc[i]] - 1) % P;
else val = 2ll * cc[cyc[i]] * cc[cyc[j]] % P;
auto add = [&](int c, int v)
{
for (pii d : fac[c])
{
int p = d.first, e = d.second;
now = 1ll * now * inv[*cycc[p].rbegin()] % P;
if (v == 1) cycc[p].insert(e);
else cycc[p].erase(cycc[p].find(e));
now = 1ll * now * *cycc[p].rbegin() % P;
}
};
add(cyc[i] + cyc[j], 1); add(cyc[i], -1); add(cyc[j], -1);
(ans += 1ll * cyc[i] * cyc[j] % P * val % P * now % P) %= P;
add(cyc[i] + cyc[j], -1); add(cyc[i], 1); add(cyc[j], 1);
}
printf("%d\n", ans);
}
return 0;
}
代码大概是仿的 RSY 的 .
以下是博客签名,正文无关
本文来自博客园,作者:yspm,转载请注明原文链接:https://www.cnblogs.com/CDOI-24374/p/17133196.html
版权声明:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0)进行许可。看完如果觉得有用请点个赞吧 QwQ
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探
2022-02-18 丽泽普及2022交流赛day21 社论