1 条题解
-
0
自动搬运
来自洛谷,原作者为

LZDQ
**搬运于
2025-08-24 22:08:20,当前版本为作者最后更新于2019-02-07 12:05:46,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
看完求点赞,我每看一篇不管好不好都点赞的
我看没人写,自己随便写一点吧
这题其实很像小学奥数
简化题目:对于每个花田,只要求有多少种情况这个花田会被采到。
也就是说,这个花田前面不能有它的因子,求排列总数。
首先我们考虑的是,一个花田有多少个因子。
排列时,这个花田必须排在所有它的因子前面,剩下不是它的因子的数,随便排
小学奥数闪亮登场
先看看一组自己的数据
6 1 1 2 2 2 3我们只考虑3的排列
根据小学奥数,先把3和两个1排好
3 1 1当然,两个1的位置可以随意排列,先把方案数乘
接着把剩下的三个数,三个2随意在这些空位放
第一个2,可以放在以下位置:
_ 3 _ 1 _ 1 _方案数乘4
第二个2有5个位置可以放,方案数乘5
以此类推
注意最后会乘到 n ,我比赛的时候没发现结果还绕弯路打 st 表,不过还是过了
有人会问,要不要乘
不用,因为已经是随便排的了
细节问题
求一个花田在其他花田中有多少个因子
这里不能用 的暴力,必须优化
我们可以用桶排,从小到大枚举,枚举到一个数就把它的倍数用另一个桶表示
复杂度 $O(10^5*(1+\frac{1}{2}+\frac{1}{3}+\frac{1}{4}+...+\frac{1}{10^5}))$
用 cnta 数组表示花田为 i 的数量(这句话看不懂可以看代码)
for(int i=1;i<=n;i++){ int a; //花的数量 scanf("%d",&a); //读入 cnta[a]++; //桶排 }接着,用 cntb 数组表示这个数有多少个因子
for(int i=1;i<=1e5;i++) //枚举桶 if(cnta[i]){ //如果有这个数 for(int j=i;j<=1e5;j+=i) //枚举倍数 cntb[j]+=cnta[i]; //这段代码看这里 }然后,if 语句后面有大括号,就是求解过程
注意 cntb 那里 i 也是算了的,因为可能有多个相同的数,比如样例中有两个3。这是为了数组表意更明确,因子也包括自己
已知一个数有 x 个因子,方案数为:
变成 这里要注意,有取模,所以我们不能把 存下来再除以 x
其实刚才那个已经可以 求解了
用一个数组表示 ,另一个数组表示
这两个东西都是 预处理的
于是这题就到此为止了
代码
#include<cstdio> const int MAXN=1e5+5,MOD=998244353; int n; int f1[MAXN],f2[MAXN]; int cnta[MAXN],cntb[MAXN]; int ans; int main(){ scanf("%d",&n); f1[0]=1; for(int i=1;i<=n;i++) f1[i]=1ll*f1[i-1]*i%MOD; f2[n+1]=1; for(int i=n;i>0;i--) f2[i]=1ll*f2[i+1]*i%MOD; for(int i=1;i<=n;i++){ int a; scanf("%d",&a); cnta[a]++; } for(int i=1;i<=1e5;i++) if(cnta[i]){ for(int j=i;j<=1e5;j+=i) cntb[j]+=cnta[i]; ans=(ans+1ll*i*cnta[i]%MOD*f1[cntb[i]-1]%MOD*f2[cntb[i]+1]%MOD)%MOD; } printf("%d\n",ans); return 0; }话说这是“超水的签到题”吗,还有紫题啊,我这个初一的蒟蒻还能做出来,不可思议!
看完博客记得点赞啊,我每看一篇都点的
- 1
信息
- ID
- 4176
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 4
- 标签
- (无)
- 递交数
- 0
- 已通过
- 0
- 上传者