题目大意:对于一个序列,定义它的价值是它的所有前缀的 $\gcd$ 中互不相同的数的个数。给定整数 $n$,问在 $1$ 到 $n$ 的排列中,有多少个排列的价值达到最大值。答案对 $10^9+7$ 取模。

$2\le n\le 10^6$。


一道 Div. 2 的难度 2500 的题,真的不是吹的……

首先考虑排列的第一个数 。假如分解质因子后为 $\prod p_i^{c_i}$,那么此时排列价值的最大值为 $\sum c_i$。

为什么?因为如果 $\gcd$ 变了,那么一定变成原来 $\gcd$ 的约数。每次变化 $\sum c_i$ 至少 $-1$。所以最大值就是 $\sum c_i$。

那么排列的价值达到最大值,只有在第一个数的 $\sum c_i$ 达到最大值才可能,并且每次 $\gcd$ 变化只会令 $\sum c_i$ 减小 $1$。

首先发现,质因子 $p_i$ 中不会有 $\ge 5$ 的数。因为此时可以把 $p_i$ 变成 $2^2$,约数更多且仍然合法。

然后,设分解质因子后 $3$ 的次数为 $c$,那么 $0\le c\le 1$。因为当 $c\ge 2$ 时,可以把 $3^2$ 变成 $2^3$,约数更多且仍然合法。

所以第一个数可以被表示成 $2^x3^y$,其中 $y\in\{0,1\}$。

那么就能上DP了。(为什么每次都那么突然……)

设 $f[i][x][y]$ 表示目前填了前 $i$ 位,当前的 $\gcd$ 是 $2^x3^y$,的总合法序列数。

初始状态 $f[1][\lfloor\log_2n\rfloor][0]=1$。如果 $2^{\lfloor\log_2n\rfloor-1}\times 3\le n$,那么还有 $f[1][\lfloor\log_2n\rfloor-1][1]=1$。其它的状态无用,只有这两个状态的 $x+y$ 达到了最大值。

答案为 $f[n][0][0]$。因为排列包含 $1$,所以 $\gcd$ 一定会变为 $1$。

如何转移?(以下设 $cnt(x)=\lfloor\frac{n}{x}\rfloor$,即 $x$ 的倍数的个数)

  • $\gcd$ 不变。那么 $f[i][x][y]+=f[i-1][x][y](cnt(2^x3^y)-(i-1))$。因为新选择的数可以是且一定是 $2^x3^y$ 的倍数。然而前 $i-1$ 个位置都是 $2^x3^y$ 的倍数,所以要减掉。
  • $\gcd/2$,也就是 $x--$(此时要求 $x<\lfloor\log_2n\rfloor$)。那么 $f[i][x][y]+=f[i-1][x+1][y](cnt(2^x3^y)-cnt(2^{x+1}3^y))$。因为新选择的数一定是 $2^x3^y$ 的倍数,但一定不是 $2^{x+1}3^y$ 的倍数(否则 $\gcd$ 不变)。前 $i-1$ 个位置都是 $2^{x+1}3^y$ 的倍数,所以不用减掉。
  • $\gcd/3$,也就是 $y--$(此时要求 $y=0$)。那么 $f[i][x][y]+=f[i-1][x][y+1](cnt(2^x3^y)-cnt(2^x3^{y+1}))$。

时间复杂度 $O(n\log n)$。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int maxn=,mod=;
#define MP make_pair
#define PB push_back
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline ll read(){
char ch=getchar();ll x=,f=;
while(ch<'' || ch>'') f|=ch=='-',ch=getchar();
while(ch>='' && ch<='') x=x*+ch-'',ch=getchar();
return f?-x:x;
}
int n,lt,f[maxn][][];
inline int cnt(int x){return n/x;}
int main(){
n=read();
lt=log2(n);
f[][lt][]=;
if((<<(lt-))*<=n) f[][lt-][]=;
FOR(i,,n) FOR(j,,lt){
f[i][j][]=(1ll*f[i-][j][]*(cnt(<<j)-(i-))+1ll*f[i-][j+][]*(cnt(<<j)-cnt(<<(j+)))+1ll*f[i-][j][]*(cnt(<<j)-cnt((<<j)*)))%mod;
f[i][j][]=(1ll*f[i-][j][]*(cnt((<<j)*)-(i-))+1ll*f[i-][j+][]*(cnt((<<j)*)-cnt((<<(j+))*)))%mod;
}
printf("%d\n",f[n][][]);
}

CF1174E Ehab and the Expected GCD Problem(DP,数论)的更多相关文章

  1. CF1174E Ehab and the Expected GCD Problem(动规+数论+分解)

    做法 先来填第一个数,为了保证\(f(p)\)最大,第一个数分解一下为\(\prod\limits_{p_i}p_i^{k_i}\)使得\(\sum\limits_{k_i}\)最大 显然第一个数为\ ...

  2. Codeforces Round #563 (Div. 2) E. Ehab and the Expected GCD Problem

    https://codeforces.com/contest/1174/problem/E dp 好题 *(if 满足条件) 满足条件 *1 不满足条件 *0 ///这代码虽然写着方便,但是常数有点大 ...

  3. codeforces#1157D. Ehab and the Expected XOR Problem(构造)

    题目链接: http://codeforces.com/contest/1174/problem/D 题意: 构造一个序列,满足以下条件 他的所有子段的异或值不等于$x$ $1 \le a_i< ...

  4. 【CF1174D】 Ehab and the Expected XOR Problem - 构造

    题面 Given two integers \(n\) and \(x\), construct an array that satisfies the following conditions: · ...

  5. CF1174D Ehab and the Expected XOR Problem

    思路: 使用前缀和技巧进行问题转化:原数组的任意子串的异或值不能等于0或x,可以转化成前缀异或数组的任意两个元素的异或值不能等于0或x. 实现: #include <bits/stdc++.h& ...

  6. CF1174D Ehab and the Expected XOR Problem(二进制)

    做法 求出答案序列的异或前缀和\(sum_i\),\([l,r]\)子段异或和可表示为\(sum_r\bigoplus sum_{l-1}\) 故转换问题为,填\(sum\)数组,数组内的元素不为\( ...

  7. CF D. Ehab and the Expected XOR Problem 贪心+位运算

    题中只有两个条件:任意区间异或值不等于0或m. 如果只考虑区间异或值不等于 0,则任意两个前缀异或值不能相等. 而除了不能相等之外,还需保证不能出现任意两个前缀异或值不等于m. 即 $xor[i]$^ ...

  8. Codeforces 798C - Mike and gcd problem(贪心+数论)

    题目链接:http://codeforces.com/problemset/problem/798/C 题意:给你n个数,a1,a2,....an.要使得gcd(a1,a2,....an)>1, ...

  9. Codeforces 1088E Ehab and a component choosing problem

    Ehab and a component choosing problem 如果有多个连接件那么这几个连接件一定是一样大的, 所以我们先找到值最大的连通块这个肯定是分数的答案. dp[ i ]表示对于 ...

随机推荐

  1. 部门工资前三高的所有员工 - LeetCode

    Employee 表包含所有员工信息,每个员工有其对应的工号 Id,姓名 Name,工资 Salary 和部门编号 DepartmentId . +----+-------+--------+---- ...

  2. [转帖]几张图让你看懂WebAssembly

    几张图让你看懂WebAssembly https://www.jianshu.com/p/bff8aa23fe4d     (图片来源:giphy.com) 编者按:本文由明非在众成翻译平台上翻译. ...

  3. 深入V8引擎-默认Platform之mac篇(2)

    先说结论,V8引擎在默认Platform中初始化的这个线程是用于处理类似于setTimeout的延时任务. 另外附一些图,包括继承树.关键属性归属.纯逻辑工作流程,对代码木得兴趣的看完图可以X掉了. ...

  4. C# 操作LDAP

    C# 操作LDAP查找组或人员信息 using System; using System.Collections.Generic; using System.Linq; using System.We ...

  5. gentelella 开源后台使用记录

    前言 gentelella是一款开源后台,github地址是:https://github.com/ColorlibHQ/gentelella 使用 表单验证 parsley 验证 在form.htm ...

  6. python 练习题:计算的BMI指数,并根据BMI指数条件选择

    小明身高1.75,体重80.5kg.请根据BMI公式(体重除以身高的平方)帮小明计算他的BMI指数,并根据BMI指数:低于18.5:过轻18.5-25:正常25-28:过重28-32:肥胖高于32:严 ...

  7. 10、VUE路由技术

    1.前端路由 前端路由在很多开源的js类库框架中都得到支持,如AngularJS.Backbone.Vue.js等等. 前端路由和后端路由原理一样,是让所有的交互和展示在一个页面运行,以达到减少服务器 ...

  8. layui 动态表格设置单元格样式

    col.push({ field: , templet: function (d) { ") { return '<span style="color:white;backg ...

  9. CountDownEvent 信号类来等待直到一定数量的操作完成

    当主程序启动时,创建一个 CountDownEvent 类的实例,在其构造函数中指定个数操作完成发出信号,当前为2个操作完成会发出信号. /// <summary> /// 创建 Coun ...

  10. 设计模式之(十三)外观模式(Facade)

    外观模式思想 历史上牛人中成功逆袭,实现人生辉煌的人很多,这群人最耀眼的无疑是明太祖朱元璋,从一个放牛讨饭的最低层小屌丝逆袭到人类权力顶峰开国皇帝,确实是我等膜拜的对象.在发不断的发展过程中,其实就在 ...