CF1174E Ehab and the Expected GCD Problem

前置知识

dp,简单数学

思路

  1. 显然我们需要考虑如何取到 \(f_{max}\) ,一个自然的想法是质因数分解,如果放在开头的是 \(p_1^{t_1}p_2^{t_2}..p_n^{t_n}\) 那么结果最长只能是 \(\sum_{i=1}^nt_i\) (后面对答案有贡献的只放小的,每次至少公因数的某一质因子的指数减 \(1\) ),而且这个值可以取到。
  2. 那么我们可以知道最后的答案就那坨式子的最大值。然后我们手玩可以发现,只用 \(2\) 以及 \(3\) 一定是最优,因为比如说 \(5^1\) 换成 \(2^2\) 一定更优,而且 \(3\) 最多用一次,\(3^2\) 替换成 \(2^3\) 一定更优。
  3. 根据性质,我们就可以设 \(dp_{i,es,ss}\) 表示处理了前 \(i\) 个点当前的 \(\gcd\)\(2^{es}3^{ss}\) 的方案数(因为 \(\gcd\) 的质因数只有这两种)。转移就是通过 \(\gcd\) 的变化情况来转。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+10,M=30,mod=1e9+7;
int n,cnt,f[2][M][2];
inline int add(int x,int y){
	return x+y<mod?x+y:x-mod+y;
}
inline void upd(int &x,int y){x=add(x,y);return ;} 
int c(int x){return n/x;}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n;
	for(cnt=0;(1<<cnt)<=n;cnt++);cnt--; 
	f[1][cnt][0]=1;
	if((1<<(cnt-1))*3<=n)f[1][cnt-1][1]=1;//初始化
	for(int i=2;i<=n;i++)
	{
		for(int x=0;x<=cnt;x++)
		{
			int lx1=i&1,lx2=(i-1)&1;
			f[lx1][x][0]=f[lx1][x][1]=0;
			upd(f[lx1][x][0],f[lx2][x][0]*add(c((1<<x)),mod-(i-1))%mod);
			upd(f[lx1][x][1],f[lx2][x][1]*add(c((1<<x)*3),mod-(i-1))%mod);//gcd不变的转移
			upd(f[lx1][x][0],f[lx2][x+1][0]*add(c(1<<x),mod-c(1<<(x+1)))%mod);
			upd(f[lx1][x][1],f[lx2][x+1][1]*add(c((1<<x)*3),mod-c((1<<(x+1))*3))%mod);//gcd x-1的转移
			upd(f[lx1][x][0],f[lx2][x][1]*add(c(1<<x),mod-c((1<<x)*3))%mod);//gcd y-1的转移
		}	
	} 
	cout<<f[n&1][0][0]<<'\n';
	return 0;
} 
posted @ 2025-05-09 09:41  exCat  阅读(27)  评论(0)    收藏  举报