CF840C On the Bench 分析

news/2025/11/9 19:24:29/文章来源:https://www.cnblogs.com/high-sky/p/19204728

题目概述

题目链接:https://www.luogu.com.cn/problem/CF840C。

给你 \(n\) 给数,将他们排列成一个序列并满足相邻两项 \(a_i,a_{i+1}\) 相乘不为平方数。问方案。

分析

我只说明一种解法,其他类的解法总结见:https://www.luogu.com.cn/article/nf3ftw8t。

注意到相邻两项的乘积不是平方数,要么是神秘题目,要么就是性质。

考虑怎么判断两个数 \(a,b\) 相乘是平方数,我们肯定先把他们的平方因子去掉,然后就变成了 \(a=n^2x,b=m^2y\),那么当 \(ab\) 为平方数时,当且仅当 \(x=y\)

也就是说这道题目转化为了一个相邻两个数不相等的方案。

所以感觉很经典就记录了一下。

像这样的题目(类似求排列方案的)一般考虑用桶分类然后一类一类地插入到序列当中,所以就是有一种计数dp叫做插入dp,其中有一个小类是连续子段dp。

那么先对这个数进行离散化然后记录,枚举每种数,并记数量为 \(cnt_i\)

不难想到设 \(f_{i,j}\) 表示考虑了前 \(i\) 种数,现在有 \(j\) 个相邻的不合法的位置的方案。

显然是由 \(f_{i-1,j}\rightarrow f_{i,?}\)

现在考虑怎么将第 \(i\) 种数插入进去呢?那么我们可以类似地想到分成 \(k\) 个部分然后分别插入到某些位置。

那么问题在于这类的方案是什么呢?记为 \(g_{i,j}\) 表示 \(i\) 个数分成 \(j\) 个部分的方案(类似于斯特林数)。

那么转移是比较显然的:

\[g_{i,j}=g_{i-1,j-1}\times j+g_{i-1,j}\times(i-1+j) \]

为什么是 \((i-1+j)\) 呢,这就是我当前这个数可以插入到任意一个块,也就是说插在头有 \(j\) 种,插在中间和末尾有 \(i-1\) 种。

然后我们再考虑怎么转移 \(f\)

对于 \(f_{i-1,j}\) 对谁有贡献呢?

我们枚举 \(k\) 表示分成 \(k\) 个部分,枚举 \(l\) 表示要从这 \(j\) 个不合法的位置选出 \(l\) 个将 \(k\) 个中的一些插入进去,最后剩下的块就在剩下的位置里面选。

转移即为:

\[f_{i,j-l+cnt_i-k}=\sum f_{i-1,j}\times g_{cnt_i,k}\times\binom{j}{l}\binom{sum+1-j}{k-l} \]

其中 \(sum\) 前面位置的个数。

为什么不对选出来的方案来个阶乘呢?这是因为我们求 \(g\) 的时候已经考虑到了顺序。

代码

时间复杂度 \(\mathcal{O}(n^2\sum cnt_i)=\mathcal{O}(n^3)\)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stdlib.h>
#include <algorithm>
#include <vector>
#define int long long
#define N 305
#define getid(x) (lower_bound(ls.begin(),ls.end(),x) - ls.begin() + 1)
using namespace std;
const int mod = 1e9 + 7;
int jc[N],inv[N];
int C(int a,int b) {if (a < 0 || b < 0 || a < b) return 0;return jc[a] * inv[b] % mod * inv[a - b] % mod;
}
int n,a[N],cnt[N],g[N][N],f[N][N];
void pls(int &x,int y) {(x += y) %= mod;
}
signed main(){jc[0] = jc[1] = inv[0] = inv[1] = 1;for (int i = 2;i < N;i ++) jc[i] = jc[i - 1] * i % mod,inv[i] = (mod - mod / i) * inv[mod % i] % mod;for (int i = 2;i < N;i ++) inv[i] = inv[i - 1] * inv[i] % mod;cin >> n;vector<int> ls;for (int i = 1;i <= n;i ++) scanf("%lld",&a[i]);for (int i = 1;i <= n;i ++) {int x = a[i];a[i] = 1;for (int j = 2;j * j <= x;j ++)if (x % j == 0) {int cntx = 0;while(x % j == 0) cntx ++,x /= j;if (cntx & 1) a[i] *= j;}a[i] *= x;ls.push_back(a[i]);}stable_sort(ls.begin(),ls.end());ls.erase(unique(ls.begin(),ls.end()),ls.end());for (int i = 1;i <= n;i ++) a[i] = getid(a[i]),cnt[a[i]] ++;int m = ls.size();g[0][0] = 1;for (int i = 1;i <= n;i ++)for (int j = 1;j <= i;j ++)g[i][j] = (g[i - 1][j - 1] * j % mod + g[i - 1][j] * (i + j - 1) % mod) % mod;int sum = 0;f[0][0] = 1;for (int i = 1;i <= m;i ++) {for (int j = 0;j <= sum;j ++)for (int k = 1;k <= cnt[i];k ++)for (int l = 0;l <= j;l ++)pls(f[i][j - l + cnt[i] - k],f[i - 1][j] * g[cnt[i]][k] % mod * C(j,l) % mod * C(sum + 1 - j,k - l) % mod);sum += cnt[i];// for (int j = 0;j <= sum;j ++) cout << f[i][j] << ' ';// cout << '\n';}cout << f[m][0];return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/960672.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HubSpot如何构建MCP服务器实现AI代理集成

HubSpot产品执行副总裁分享公司如何基于Model Context Protocol构建远程MCP服务器,详细解析技术架构选择、认证实现、与现有系统集成等核心挑战,以及AI代理在CRM领域的实际应用场景。HubSpot的MCP实现:CRM公司的AI代…

CSP-S 2025 趋势记

有个人 CSP-S 寄飞了,我不说是谁。感觉模拟赛也没啥动力打了。 T1 写了 \(10\) min 切了,非常自信。T2 写了 \(30\) min 被卡成 \(80\) 了,趋势。 然后开始传统艺能发呆,T3 看半天看错题了,看成可以替换无限次了,…

苹果手机iOS15.8.2 – 16.7.8最新越狱方法

支持设备 越狱支持所有 A9-A11 片上系统 (SoC)。您可以在下面找到兼容的 Palera1n 越狱 iPhone 和 iPad 的实际列表。越狱经过测试,可以在运行 iOS 15 的 iPhone X (GSM)、iPhone 8、iPhone 7 和 iPhone 6s上运行和工…

威联通NAS部署umami - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

后端八股之Redis - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

AGC052 VP 记录

场切 \(0\) 道题,被猜性质猜结论题气笑了. A 后来回想起来,这个题好像确实在北京集训讲过. 有 \(4\) 种合法的构造:\(0\overbrace{1\cdots1}^{n个} \overbrace{0\cdots0}^{n个}\),\(1\overbrace{0\cdots0}^{n个} \…

结合400行mini-react代码,图文解说React原理

引言: 在我学习React原理的时候,一上来看的非常全而细节的书/博客(头大),或者是看的教你实现一个简单mini-react(还是一知半解),最终学的痛苦又效果不好。所以,写了这篇博客,希望能帮助您入门React原理。此外…

UE:告别加载卡顿!一键合并StaticMeshActor方案

© mengzhishanghun 原创文章 首发于 博客园 禁止未经授权转载前言 大型UE场景打包后首次加载时,经常遇到长时间卡顿甚至假死现象。究其原因,成百上千个独立的StaticMeshActor在序列化、实例化时产生了巨大开销…

在Visual Studio使用Qt的插件机制进行开发 - 指南

在Visual Studio使用Qt的插件机制进行开发 - 指南pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas",…

摸鱼笔记[2]-提取windows已安装的驱动

使用`DriverStoreExplorer`提取windows已安装的海康相机.inf驱动文件.摘要 使用DriverStoreExplorer提取windows已安装的海康相机.inf驱动文件. 实现 [https://github.com/lostindark/DriverStoreExplorer] Driver Sto…

CF2013D 题解

提供一个二分做法。 因为当 \(a_i > a_{i + 1}\) 是做操作是不劣的,所以最终 \(a\) 一定单调不降。那么我们二分一个最小的 \(\max(a_i)\) 和最大的 \(\min(a_i)\),答案就是 \(\max(a_i) - \min(a_i)\)。 下面说一…

题解:AT_agc068_a [AGC068A] Circular Distance

牛牛题,看了很多次才看懂 题意:给出 \(L,n\),问在一个 \(L\) 长的环上,放置 \(n\) 个点,定义两点距离为两种路径中长度较短的长度,问所有放置方式的点的距离最大值之和。 做法: 首先先强制选定 \(0\) 号点,最后…

P14461 题解

消一消元: \[\begin{aligned}F_i&= G_{i - 1} + G_{i - 1} \\&= F_{i - 2} - F_{i - 2} + F_{i - 2} - F_{i - 2} \\&= F_{i - 2} - F_{i - 2} \end{aligned} \]类似的: \[G_i = G_{i - 2} - G_{i - 2} …

Nim 游戏与 SG 函数

已完成今日《Nim 游戏与 SG 函数》大学习。 本文比较基础,并未涉及到各种各样的 Nim 游戏,因为笔者比较菜。 1. 公平组合游戏 定义一个游戏为公平组合游戏,当且仅当:双方都知道当前局面的所有信息。 每一步的操作与…

题解:Luogu P11114 [ROI 2024] 小推车 (Day 1)

题意 有一排编号为 \(1\sim n\) 的座位。有 \(k\) 种饮料,第 \(i\) 名乘客想要喝第 \(a_i\) 种饮料。小推车需要从 \(0\) 位置出发,最终走到 \(n+1\) 位置,按顺序给每名乘客分饮料。推车上有 \(m\) 个瓶子,每个瓶子…

摸鱼笔记[1]-windows设置双网卡优先级(跃点数)

windows系统通过设置跃点数以设置双网卡优先级, 实现工控局域网网卡和互联网网卡各司其职, 电脑同时访问局域网和互联网.摘要 windows系统通过设置跃点数以设置双网卡优先级, 实现工控局域网网卡和互联网网卡各司其职,…

NXP - 用MDK建立基于arm-none-eabi软件链的工程框架

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …