Codeforces 653G Move by Prime 组合数学
题意:
有一个长度为\(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\)的子序列。
考虑下面这个生成函数:
\]
- \(e_k\)在左半部分的子序列的个数为指数为负的系数之和
- \(e_k\)在右半部分的子序列的个数为指数为正的系数之和
因此\(e_k\)对所有子序列的贡献为:
\]
\]
\]
\]
而且\({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 组合数学的更多相关文章
- Codeforces 385C Bear and Prime Numbers
题目链接:Codeforces 385C Bear and Prime Numbers 这题告诉我仅仅有询问没有更新通常是不用线段树的.或者说还有比线段树更简单的方法. 用一个sum数组记录前n项和, ...
- 【CF653G】Move by Prime 组合数
[CF653G]Move by Prime 题意:给你一个长度为n的数列$a_i$,你可以进行任意次操作:将其中一个数乘上或者除以一个质数.使得最终所有数相同,并使得操作数尽可能小.现在我们想要知道$ ...
- Codeforces 385C Bear and Prime Numbers(素数预处理)
Codeforces 385C Bear and Prime Numbers 其实不是多值得记录的一道题,通过快速打素数表,再做前缀和的预处理,使查询的复杂度变为O(1). 但是,我在统计数组中元素出 ...
- codeforces 385C Bear and Prime Numbers 预处理DP
题目链接:http://codeforces.com/problemset/problem/385/C 题目大意:给定n个数与m个询问区间,问每个询问区间中的所有素数在这n个数中被能整除的次数之和 解 ...
- codeforces 932E Team Work(组合数学、dp)
codeforces 932E Team Work 题意 给定 \(n(1e9)\).\(k(5000)\).求 \(\Sigma_{x=1}^{n}C_n^xx^k\). 题解 解法一 官方题解 的 ...
- Codeforces 840C 题解(DP+组合数学)
题面 传送门:http://codeforces.com/problemset/problem/840/C C. On the Bench time limit per test2 seconds m ...
- codeforces 659 G. Fence Divercity 组合数学 dp
http://codeforces.com/problemset/problem/659/G 思路: f(i,0/1,0/1) 表示到了第i个,要被切的块开始了没有,结束了没有的状态的方案数 递推看代 ...
- codeforces 679A Bear and Prime 100 交互
第一次交互题,记录一下吧 #include <cstdio> #include <iostream> #include <ctime> #include <v ...
- CodeForces 385C Bear and Prime Numbers 素数打表
第一眼看这道题目的时候觉得可能会很难也看不太懂,但是看了给出的Hint之后思路就十分清晰了 Consider the first sample. Overall, the first sample h ...
随机推荐
- 50道CSS基础面试题(附答案)
1 介绍一下标准的CSS的盒子模型?与低版本IE的盒子模型有什么不同的? 标准盒子模型:宽度=内容的宽度(content)+ border + padding + margin低版本IE盒子模型:宽度 ...
- jQuery中$(function(){})与(function($){})(jQuery)、$(document).ready(function(){})等的区别讲解
1.(function($){...})(jQuery); (1).原理: 这实际上是匿名函数,如下: function(arg){...} 这就定义了一个匿名函数,参数为arg:而调用函 ...
- Jquery里面的$(this)和this, 有什么区别
当你用的是jquery时,就用$(this),如果是JS,就用this $(this).html( $(this).html() + " BAM! "); 这个里的html()是J ...
- 软件License设计
如何保护软件版权,最常用的办法就是设计一套license验证框架. 1.我们的常规需求如下: .可以限制软件只能在一台机器上使用: 目前很多软件都是一机一码的销售,软件换一台机器则不能使用,想要几台机 ...
- CentOs7 修复 引导启动
一.修复MBR: MBR(Master Boot Record主引导记录): 硬盘的0柱面.0磁头.1扇区称为主引导扇区.其中446Byte是bootloader,64Byte为Partition t ...
- COGS 201. [BYVoid S1] 埃雷萨拉斯的宝藏
★★ 输入文件:eldrethalas.in 输出文件:eldrethalas.out 简单对比时间限制:1 s 内存限制:256 MB 问题描述 一万两千年前,精灵还是在艾萨拉女王的 ...
- HDU1075 字典树 + 字符串映射
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1075 ,字典树的字符串映射. 题意是给你每个火星文单词对应的英语,然后让你把一篇火星文文章给翻译成英语 ...
- Android(java)学习笔记89:Bundle和Intent类使用和交互
1. Bundle 和 Intent: Bundle只是一个信息的载体 将内部的内容以键值对组织 ,Intent负责Activity之间的交互自己是带有一个Bundle的.Intent.putE ...
- oc语言特性
It’s a superset of the C programming language and provides object-oriented capabilities and a dynami ...
- FreeRTOS_软件定时器
FreeRTOS 软件定时器 实验 创建2个任务,start_task.timercontrol_task. start_stask:创建timercontrol_task任务:创建周期定时器Auto ...