题意:

有一个长度为\(n\)的正整数序列\(a\),有这样一种操作:

每次可以选序列中的某一个数乘上或除以某一个素数。

求对于每一个子序列使其所有元素相等的最少操作次数之和。

分析:

因为两个素数之间互不影响,单独考虑每一个素数\(p\)。

设当前子序列的长度为\(k\),对应的指数为\(e_1, e_2 \cdots e_k\)。

每次操作会将某一个\(e_i\)增加\(1\)或减少\(1\)。

将\(e_i\)对应到数轴上的点,每次操作就相当于让某个点向左或向右移动一个单位长度。

让它们都相等的最少操作次数就等于这些点到中位数的距离之和\(d\)。

  • \(k=4\)时,\(d=e_4+e_3-e_2-e_1\),中位数为\(e_2\)或\(e_3\)。
  • \(k=5\)时,\(d=e_5+e_4-e_2-e_1\),中位数为\(e_3\)。

下面考虑所有的子序列:

对于\(e_k\),如果它在一个子序列的左半部分那么它对答案的贡献是\(-1\) ,如果它在序列的右半部分那么它对答案的贡献是\(+1\)。

可以在\(e_1, e_2 \cdots e_{k-1}\)中选若干数,以及在\(e_{k+1} \cdots e_n\)选若干数,构成包含\(e_k\)的子序列。

考虑下面这个生成函数:

\[(1+\frac{1}{x})^{k-1}+(1+x)^{n-k}=\frac{(1+x)^{n-1}}{x^{k-1}}
\]

  • \(e_k\)在左半部分的子序列的个数为指数为负的系数之和
  • \(e_k\)在右半部分的子序列的个数为指数为正的系数之和

因此\(e_k\)对所有子序列的贡献为:

\[\sum\limits_{i=k}^{n-1}C_{n-1}^i-\sum\limits_{i=0}^{k-2}C_{n-1}^i
\]

\[=\sum\limits_{i=0}^{n-1}C_{n-1}^i-\sum\limits_{i=0}^{k-1}C_{n-1}^i-\sum\limits_{i=0}^{k-2}C_{n-1}^i
\]

\[=2^{n-1}-2\sum\limits_{i=0}^{k-2}C_{n-1}^i-C_{n-1}^{k-1}
\]

\[=2^{n-1}-\sum\limits_{i=0}^{k-1}C_n^i
\]

而且\({e_i}\)最大不会超过\(20\),所以统计一下每个\(e_i\)出现的次数,再预处理一下组合数的前缀和的前缀和。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; typedef long long LL;
const LL MOD = 1000000007; LL mul(LL a, LL b) { return a * b % MOD; } void add(LL& a, LL b) { a += b; if(a >= MOD) a -= MOD; } void sub(LL& a, LL b) { a -= b; if(a < 0) a += MOD; } LL pow_mod(LL a, int p) {
LL ans = 1;
while(p) {
if(p & 1) ans = mul(ans, a);
a = mul(a, a);
p >>= 1;
}
return ans;
} const int maxn = 300000 + 10;
const int maxp = 26000; bool vis[maxn];
int prime[maxp], pid[maxn], pcnt; void preprocess() {
for(int i = 2; i < maxn; i++) {
if(!vis[i]) { prime[pcnt] = i; pid[i] = pcnt++; }
for(int j = 0; j < pcnt; j++) {
if(i * prime[j] >= maxn) break;
vis[i * prime[j]] = true;
if(i % prime[j] == 0) break;
}
}
} int n, a[maxn];
int cnt[maxp][20]; LL fac[maxn], inv[maxn], Cn[maxn]; void decompose(int x) {
for(int i = 0; x > 1; i++) {
int p = prime[i];
if(p * p > x) break;
if(x % p != 0) continue;
int e = 0;
while(x % p == 0) { x /= p; e++; }
cnt[i][e]++;
}
if(x > 1) cnt[pid[x]][1]++;
} int main()
{
preprocess(); scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", a + i); fac[0] = 1;
for(int i = 1; i <= n; i++) fac[i] = mul(fac[i - 1], i);
inv[n] = pow_mod(fac[n], MOD - 2);
for(int i = n - 1; i >= 0; i--) inv[i] = mul(inv[i + 1], i + 1);
for(int i = 0; i <= n; i++) Cn[i] = mul(mul(fac[n], inv[i]), inv[n - i]);
for(int i = 1; i <= n; i++) add(Cn[i], Cn[i - 1]);
for(int i = 1; i <= n; i++) add(Cn[i], Cn[i - 1]); for(int i = 1; i <= n; i++) decompose(a[i]); LL ans = 0;
LL S = pow_mod(2, n - 1);
for(int i = 0; i < pcnt; i++) {
int tot = n;
for(int j = 1; j < 20; j++) tot -= cnt[i][j];
for(int j = 1; j < 20; j++) if(cnt[i][j]) {
int L = tot, R = L + cnt[i][j] - 1;
tot += cnt[i][j];
LL t = Cn[R];
if(L) sub(t, Cn[L - 1]);
sub(t, mul(S, cnt[i][j]));
add(ans, mul(t, j));
}
} printf("%lld\n", ans); return 0;
}

Codeforces 653G Move by Prime 组合数学的更多相关文章

  1. Codeforces 385C Bear and Prime Numbers

    题目链接:Codeforces 385C Bear and Prime Numbers 这题告诉我仅仅有询问没有更新通常是不用线段树的.或者说还有比线段树更简单的方法. 用一个sum数组记录前n项和, ...

  2. 【CF653G】Move by Prime 组合数

    [CF653G]Move by Prime 题意:给你一个长度为n的数列$a_i$,你可以进行任意次操作:将其中一个数乘上或者除以一个质数.使得最终所有数相同,并使得操作数尽可能小.现在我们想要知道$ ...

  3. Codeforces 385C Bear and Prime Numbers(素数预处理)

    Codeforces 385C Bear and Prime Numbers 其实不是多值得记录的一道题,通过快速打素数表,再做前缀和的预处理,使查询的复杂度变为O(1). 但是,我在统计数组中元素出 ...

  4. codeforces 385C Bear and Prime Numbers 预处理DP

    题目链接:http://codeforces.com/problemset/problem/385/C 题目大意:给定n个数与m个询问区间,问每个询问区间中的所有素数在这n个数中被能整除的次数之和 解 ...

  5. codeforces 932E Team Work(组合数学、dp)

    codeforces 932E Team Work 题意 给定 \(n(1e9)\).\(k(5000)\).求 \(\Sigma_{x=1}^{n}C_n^xx^k\). 题解 解法一 官方题解 的 ...

  6. Codeforces 840C 题解(DP+组合数学)

    题面 传送门:http://codeforces.com/problemset/problem/840/C C. On the Bench time limit per test2 seconds m ...

  7. codeforces 659 G. Fence Divercity 组合数学 dp

    http://codeforces.com/problemset/problem/659/G 思路: f(i,0/1,0/1) 表示到了第i个,要被切的块开始了没有,结束了没有的状态的方案数 递推看代 ...

  8. codeforces 679A Bear and Prime 100 交互

    第一次交互题,记录一下吧 #include <cstdio> #include <iostream> #include <ctime> #include <v ...

  9. CodeForces 385C Bear and Prime Numbers 素数打表

    第一眼看这道题目的时候觉得可能会很难也看不太懂,但是看了给出的Hint之后思路就十分清晰了 Consider the first sample. Overall, the first sample h ...

随机推荐

  1. 【Python】python2 str 编码检测

    python2 str 编码检测 import chardet s = 'sdffdfd' print type(s) print chardet.detect(s) s2 = '反反复复' prin ...

  2. 基于screen.width的伪响应式开发

    一.站在用户的角度看问题 一个用户,访问一个web页面的真实场景是怎样的呢? 下面是某用户访问某站点的一个场景: 1. 小明打开了自己的电脑,访问了鑫空间-鑫生活: 2. 小明体内洪荒之力无法控制,疯 ...

  3. 【干货】JavaScript DOM编程艺术学习笔记4-6

    四.案例研究:JavaScript图片库 js: function showPic(whichpic){ //取得链接 var source=whichpic.getAttribute("h ...

  4. mybatis 异常处理:Invalid bound statement (not found)

    mybatis 的使用过程中提示错误: org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): ...

  5. HTML和CSS一般有哪些功能?(聊~平时常出现的那些知识)

    简单一点点 HTML行内标签有哪些? 一般行内的标签包含哪些? 如:a - 锚点, span - 常用内联或定义块级容器, i - 斜体, b - 粗体, strong - 粗体强调, var - 定 ...

  6. 302和VS启动后网站拒绝访问的解决方案

    网页状态302代表的是重定向的意思,就是网页跳转的一种状态 网站拒绝访问的时候可以在输出窗口查看是否有内容输出,如果没有说明启动网站的端口可能被占用,在网站项目——属性——web——项目中把地址的端口 ...

  7. 【BZOJ3994】[SDOI2015] 约数个数和(莫比乌斯反演)

    点此看题面 大致题意: 设\(d(x)\)为\(x\)的约数个数,求\(\sum_{i=1}^N\sum_{j=1}^Md(i·j)\). 莫比乌斯反演 这是一道莫比乌斯反演题. 一个重要的性质 首先 ...

  8. squid如何屏蔽User-Agent为空的请求

    搞定了,反过来就行了acl has_user_agent browser ^ http_access deny !has_user_agent

  9. python剑指offer 合并两个排序的链表

    题目描述 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则. # -*- coding:utf-8 -*- # class ListNode: # def _ ...

  10. 使用Vue CLI 3快速创建项目

    首先 vue create ant-design-vue-pro 执行命令会显示两个选项,1默认,2自定义 我么选择自定义 选择好自定义的插件回车就等待下安装成功然后进入项目文件夹 cd ant-de ...