题目大意:对于一个序列,定义它的价值是它的所有前缀的 $\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. Eureka与Zookeeper的区别

    ACID与ACP的介绍

  2. Scala中sortBy和Spark中sortBy区别

    Scala中sortBy是以方法的形式存在的,并且是作用在Array或List集合排序上,并且这个sortBy默认只能升序,除非实现隐式转换或调用reverse方法才能实现降序,Spark中sortB ...

  3. HTML--元素居中各种处理方法2

    紧接上一篇. 如果要居中的是一个块元素呢. 1)如果你知道这个块元素的高度: <main> <div> I'm a block-level element with a fix ...

  4. Git拉取远程分支命令

    如果我们想从Git仓库中拉取一个分支到本地,此处假如远程分支为develop,本地要创建的分支为dev,可以使用以下命令: git init    //初始化本地Git仓库 git remote ad ...

  5. 分享windows 10 下部署 elasticsearch 和 logstash

    最近和es杠上了.以前只听说过es一直没有机会体验一下. 最近有点时间,就着手体验一把.因为是第一次接触es,没有任何基础.入门的第一件是就是用 百度了, [不过建议改名为白度,基本上查不到想要的,一 ...

  6. C# FastReport .NET打印

    引用DLL : FastReport.dll FastReport.Report sender = new FastReport.Report(); try { sender.Load("f ...

  7. Queue接口分析:add和offer区别,remove和poll方法到底啥区别

    Queue接口: public interface Queue<E> extends Collection<E> { /* * add方法,在不违背队列的容量限制的情况,往队列 ...

  8. 《Netty 权威指南(第2 版)》目录

    图书简介:<Netty 权威指南(第2 版)>是异步非阻塞通信领域的经典之作,基于最新版本的Netty 5.0 编写,是国内很难得一见的深入介绍Netty 原理和架构的书籍,也是作者多年实 ...

  9. 2019 多点Dmalljava面试笔试题 (含面试题解析)

      本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.多点Dmall等公司offer,岗位是Java后端开发,因为发展原因最终选择去了多点Dmall,入职一年时间了 ...

  10. git操作:撤销更改的文件

    在没有git add之前: #撤销所有更改 git checkout . #撤销指定文件的更改 git checkout -- myfile.txt 在git add之后: git reset HEA ...