这是一个很菜的 Oier 的博客|

Hanx16Msgr

园龄:2年8个月粉丝:12关注:3

2024-01-27 21:39阅读: 15评论: 0推荐: 0

CF1174E Ehab and the Expected GCD Problem

Ehab and the Expected GCD Problem

Luogu CF1174E

题目描述

p 是一个排列,定义 f(p) : 设 gip1,p2,,pi 的最大公因数(即前缀最大公因数),则 f(p)g1,g2,,gn 中不同的数的个数。

fmax(n)1,2,,n 的所有排列 pf(p) 的最大值,你需要求有多少 1,2,,n 的排列 p 满足 f(p)=fmax(n),答案对 109+7 取模。

Solution

考虑第一个数为 x,那么为了使得不同的数的个数最多,将 x 进行质因数分解,每次一定只能将指数 1,否则一定不优。为了使得减的次数最多,那么 x 一定是由 2a×3b(b{0,1}) 构成,因为如果出现 532 都可以变成 22

考虑 DP 这一个前缀 gcd。设 f(i,j,k) 表示当前在位置 i,前缀 gcd2j×3k 的方案数。记 g(x)=nx 表示 n 以内 x 的倍数的个数。那么有转移:

  • gcd 不变,那么 f(i,j,k)f(i1,j,k)(g(2j×3k)(i1))
  • gcd2 的指数 1,那么 f(i,j,k)f(i1,j+1,k)(g(2j×3k)g(2j+1×3k))
  • gcd3 的指数 1,那么 f(i,j,k)f(i1,j,k+1)(g(2j×3k)g(2j×3k+1))

时间复杂度 O(nlogn)

Code
int N, lst = 0, cur = 1;
mint f[2][21][2];
signed main() {
    cin.tie(0)->sync_with_stdio(0);
    cin >> N;
    int lg = __lg(N);
    f[cur][lg][0] = 1;
    if ((1 << (lg - 1)) * 3 <= N)
        f[cur][lg-1][1] = 1;
    For(i, 2, N) {
        swap(cur, lst);
        For(j, 0, lg) f[cur][j][0] = f[cur][j][1] = 0;
        For(j, 0, lg) {
            f[cur][j][0] += f[lst][j][0] * (N / (1 << j) - i + 1);
            f[cur][j][0] += f[lst][j+1][0] * (N / (1 << j) - N / (1 << (j + 1)));
            f[cur][j][0] += f[lst][j][1] * (N / (1 << j) - N / ((1 << j) * 3));
            f[cur][j][1] += f[lst][j][1] * (N / ((1 << j) * 3) - i + 1);
            f[cur][j][1] += f[lst][j+1][1] * (N / ((1 << j) * 3) - N / ((1 << (j + 1)) * 3));
        }
    }
    cout << f[cur][0][0] << '\n';
}
posted @   Hanx16Msgr  阅读(15)  评论(0编辑  收藏  举报
历史上的今天:
2023-01-27 230127 % 你赛
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起