「CF1174E」 Ehab and the Expected GCD Problem
\(\texttt{「CF1174E」 Ehab and the Expected GCD Problem}\)
\(\texttt{Describe}\)
给定一个有 \(n\) 个数的排列 \(p\),定义
则 \(f(p)\) 为 \(g_1\sim g_n\) 中不同的数的个数。
\(P\) 为 \(1\sim n\) 所有排列的集合。试求有多少个排列 \(p\) 满足
\(\texttt{Input Format}\)
输入一个正整数 \(n\)。
\(\texttt{Output Format}\)
输出答案对 \(10^9+7\) 取模的结果。
\(\texttt{Example In 1}\)
2
\(\texttt{Example Out 1}\)
1
\(\texttt{Example In 2}\)
3
\(\texttt{Example Out 2}\)
4
\(\texttt{Example In 3}\)
6
\(\texttt{Example Out 3}\)
120
\(\texttt{Data}\)
\(2\le n\le 10^6\)
\(\texttt{Solution}\)
考虑先分析一下 \(f\)。思考分析如果排列第一个数 \(X\) 的唯一分解形式是
此时答案的最大值显然为
因为我们可以构造一个排列满足每一个数是在上一个数中的唯一分解形式选一个 \(p_j\),将 \(c_j-1\rightarrow c_j\),这样两个数都可以造成贡献。因为每次选 \(p_j\) 所构造的数小于上一个数且构造出来的数列一定没有重复的数,所以在 \(1\sim n\) 的排列中一定可以构造处理。
考虑在 \(1\sim n\) 选一个数 \(X\) 使得 \(\text{ans}(X)\) 最大化,一个显然的事实说明当选择一个质数 \(p\ge5\) 时,不如选择两个较小质数的乘积。例如,如果选择 \(5\),我们用 \(2^2\) 替代 \(5\),比它对 \(\text{ans}\) 的贡献更大,且更小(后续有更多的“余额”去乘另外的数)。对于 \(3\),它最多选择 \(1\) 个,因为 \(3^2>2^3\),选择 \(2\) 更加划算。
所以第一个数可以是 \(2^{\lfloor\log_2n\rfloor}\) 或者 \(2^{\lfloor\log_2n\rfloor-1}\times 3\),它们对于 \(\text{ans}\) 的贡献是代价的。
所以考虑多少个排列那个符合要求。
定义 \(f_{i,j,k}\) 为已经选了前 \(i\) 个位置,当前的 \(\gcd\) 为 \(2^j3^k\)。
可以考虑三种转移方式
-
\(\gcd\rightarrow \gcd\)
要选的数一定是 \(2^j3^k\) 的倍数,同时位置 \(1\sim i-1\) 也是 \(2^j3^k\) 的倍数,所以要排除掉,所以一共有 \(\left\lfloor\dfrac{n}{2^j3^k}\right\rfloor-(i-1)\) 种转移方式。 -
\(\left\lfloor\dfrac \gcd 2\right\rfloor\rightarrow \gcd\)
要选的数一定是 \(2^j3^k\) 的倍数,同时一定不是 \(2^{j+1}3^k\) 的倍数,所以要排除掉,所以一共有 \(\left\lfloor\dfrac{n}{2^j3^k}\right\rfloor-\left\lfloor\dfrac{n}{2^{j+1}3^k}\right\rfloor\) 种转移方式。 -
\(\left\lfloor\dfrac \gcd 3\right\rfloor\rightarrow \gcd\)
要选的数一定是 \(2^j3^k\) 的倍数,同时一定不是 \(2^j3^{k+1}\) 的倍数,所以要排除掉,所以一共有 \(\left\lfloor\dfrac{n}{2^j3^k}\right\rfloor-\left\lfloor\dfrac{n}{2^j3^{k+1}}\right\rfloor\) 种转移方式。
得到状态转移方程:
\(j\) 的范围是 \(0\sim \left\lfloor\log_2{n}\right\rfloor\),\(k\) 的范围是 \(0\sim1\)。所以时间复杂度为 \(\mathcal O(n\log_2 n)\)。
\(\texttt{Code}\)
#include<bits/stdc++.h>
#define ll unsigned int
#define val(x) ((N)/(x))
#define mul(x) ((x)+(x<<1))
#define MOD (1000000007)
#define lowbit(x) (x&-x)
using namespace std;
inline void read(ll &x)
{
register char ch=0;register bool f=0;x=0;
while(ch<'0'||ch>'9'){f|=!(ch^'-');ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
x=f?-x:x;
}
ll N,limit;
ll dp[1000005][22][2];
int main()
{
read(N);
limit=log2(N);
dp[1][limit][0]=1,dp[1][limit-1][1]=(mul(1<<(limit-1))<=N)?1:0;
for(ll i=2;i<=N;i++)
{
for(ll j=0;j<=limit;j++)
{
dp[i][j][0]+=(1ll*dp[i-1][j][0]*(val(1<<j)-(i-1))+1ll*dp[i-1][j+1][0]*(val(1<<j)-val(1<<(j+1)))+1ll*dp[i-1][j][1]*(val(1<<j)-val(mul(1<<j))))%MOD;
dp[i][j][1]+=(1ll*dp[i-1][j][1]*(val(mul(1<<j))-(i-1))+1ll*dp[i-1][j+1][1]*(val(mul(1<<j))-val(mul(1<<(j+1)))))%MOD;
}
}
printf("%d",dp[N][0][0]);
}

浙公网安备 33010602011771号