题意:

给出\(M\)和\(a数组\),询问每一个\(d\in[1,M]\),有多少组数组满足:正好修改\(k\)个\(a\)数组里的数使得和原来不同,并且要\(\leq M\),并且\(gcd(a_1,a_2,\dots,a_n)=d\)。

思路:

对于每一个\(d\),即求\(f(d)\):修改\(k\)个后\(gcd(a_1,a_2,\dots,a_n)=d\)的对数。

那么假设\(F(d)\):修改\(k\)个后\(gcd(a_1,a_2,\dots,a_n)\)是\(d\)倍数的对数。故:

\[f(k) = \sum_{k|d}\mu(\frac{d}{k})F(d)
\]

打表求\(F(d)\)即可。假设\(num[d]\)为\(a\)中是\(d\)倍数的数量,则

\[F(d)=(\frac{M}{d})^{n-num[d]}*C_{num[d]}^{k-(n-num[d])}*(\frac{M}{d}-1)^{k-(n-num[d])}
\]

然后\(nlogn\)打出\(num\)数组即可。

思考:

这样的打表法是\(nlogn\)的:

证明 O(n/1+n/2+…+n/n)=O(nlogn)

for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);
num[a[i]]++;
}
for(int i = 1; i <= m; i++){
for(int j = i + i; j <= m; j += i){
num[i] += num[j];
}
}

这样是\(n\sqrt n\)的

for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);
for(int j = 1; j <= sqrt(a[i]); j++){
if(a[i] % j == 0){
num[j]++;
if(j * j != a[i]) num[a[i] / j]++;
}
}
}

代码:

#include<map>
#include<set>
#include<queue>
#include<stack>
#include<ctime>
#include<cmath>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 3e5 + 5;
const int INF = 0x3f3f3f3f;
const ull seed = 131;
const ll MOD = 1000000007;
using namespace std; int mu[maxn], vis[maxn];
int prime[maxn], cnt;
ll fac[maxn], inv[maxn];
ll ppow(ll a, ll b){
ll ret = 1;
while(b){
if(b & 1) ret = ret * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return ret;
}
void init(int n){
memset(vis, 0, sizeof(vis));
memset(mu, 0, sizeof(mu));
cnt = 0;
mu[1] = 1;
for(int i = 2; i <= n; i++) {
if(!vis[i]){
prime[cnt++] = i;
mu[i] = -1;
}
for(int j = 0; j < cnt && prime[j] * i <= n; j++){
vis[prime[j] * i] = 1;
if(i % prime[j] == 0) break;
mu[i * prime[j]] = -mu[i];
}
} fac[0] = inv[0] = 1;
for(int i = 1; i <= n; i++) fac[i] = fac[i - 1] * i % MOD;
inv[n] = ppow(fac[n], MOD - 2);
for(int i = n - 1; i >= 1; i--) inv[i] = (i + 1LL) * inv[i + 1] % MOD;
}
ll C(int n, int m){
return fac[n] * inv[m] % MOD * inv[n - m] % MOD;
}
int num[maxn], a[maxn];
//num[i]:是i的倍数的个数
ll F[maxn], f[maxn];
int main(){
init(3e5);
int n, m, k;
while(~scanf("%d%d%d", &n, &m, &k)){
memset(num, 0, sizeof(num));
for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);
num[a[i]]++;
}
for(int i = 1; i <= m; i++){
for(int j = i + i; j <= m; j += i){
num[i] += num[j];
}
}
for(int i = 1; i <= m; i++){
int no = n - num[i];
if(no > k) F[i] = 0;
else{
F[i] = ppow(m / i, no) * C(num[i], k - no) % MOD * ppow(m / i - 1, k - no) % MOD;
}
} for(int i = 1; i <= m; i++){
f[i] = 0;
for(int j = i; j <= m; j += i){
f[i] += mu[j / i] * F[j];
f[i] %= MOD;
}
printf("%lld%c", (f[i] % MOD + MOD) % MOD, i == m? '\n' : ' ');
} }
return 0;
}

HDU 4675 GCD of Sequence(莫比乌斯反演 + 打表注意事项)题解的更多相关文章

  1. 数学--数论--HDU 4675 GCD of Sequence(莫比乌斯反演+卢卡斯定理求组合数+乘法逆元+快速幂取模)

    先放知识点: 莫比乌斯反演 卢卡斯定理求组合数 乘法逆元 快速幂取模 GCD of Sequence Alice is playing a game with Bob. Alice shows N i ...

  2. HDU - 4675 GCD of Sequence (莫比乌斯反演+组合数学)

    题意:给出序列[a1..aN],整数M和k,求对1-M中的每个整数d,构建新的序列[b1...bN],使其满足: 1. \(1 \le bi \le M\) 2. \(gcd(b 1, b 2, -, ...

  3. HDU 4675 GCD of Sequence (2013多校7 1010题 数学题)

    GCD of Sequence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)T ...

  4. HDU 4675 GCD of Sequence(容斥)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4675 题意:给出n,m,K,一个长度为n的数列A(1<=A[i]<=m).对于d(1< ...

  5. hdu 4675 GCD of Sequence

    数学题! 从M到1计算,在计算i的时候,算出原序列是i的倍数的个数cnt: 也就是将cnt个数中的cnt-(n-k)个数变掉,n-cnt个数变为i的倍数. 且i的倍数为t=m/i; 则符合的数为:c[ ...

  6. 【CJOJ2512】gcd之和(莫比乌斯反演)

    [CJOJ2512]gcd之和(莫比乌斯反演) 题面 给定\(n,m(n,m<=10^7)\) 求 \[\sum_{i=1}^n\sum_{j=1}^mgcd(i,j)\] 题解 首先把公因数直 ...

  7. HDU 2841 Visible Trees(莫比乌斯反演)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2841 题意:给n*m的矩阵(从(1,1)开始编号)格子,每个格子有一棵树,人站在(0,0)的位置,求可 ...

  8. hdu4675 GCD of Sequence 莫比乌斯+组合数学

    /** 题目:hdu4675 GCD of Sequence 链接:http://acm.hdu.edu.cn/showproblem.php?pid=4675 题意:给定n个数的a数组,以及m,k: ...

  9. bnu——GCD SUM (莫比乌斯反演)

    题目:GCD SUM 题目链接:http://www.bnuoj.com/v3/problem_show.php?pid=39872 算法:莫比乌斯反演.优化 #include<stdio.h& ...

随机推荐

  1. Shell从入门到精通

    熟悉基本shell操作不仅是运维的基本功,对于开发来说也是多多益善,我在学习的过程中,总结了十个练手的小demo,并附上涉及的知识点,仅供娱乐. 1. 多线程ping监控,检查同一网段的IP是否连通 ...

  2. http2 http1 对比

    RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2) https://tools.ietf.org/html/rfc7540#page-4 ...

  3. 命名规范 api-guidelines api规范

    https://weui.io weui.css .weui-cell_select-before .weui-cell__bd:after{ display:none; } .weui-cell_s ...

  4. 切片声明 切片在内存中的组织方式 reslice

    数组是具有相同 唯一类型 的一组已编号且长度固定的数据项序列(这是一种同构的数据结构),[5]int和[10]int是属于不同类型的.数组的编译时值初始化是按照数组顺序完成的(如下). 切片声明方式, ...

  5. 深信服edr控制中心漏洞——代码执行

    第一处代码执行 文件:tool/php_cli.php第64行

  6. io流读写操作

    /** * * DOC 将F盘下的test.jpg文件,读取后,再存到E盘下面. * * @param args * @throws Exception */ public static void m ...

  7. checkAll操作

    //全部勾选 function checkAll(obj) { var cols = document.getElementsByName('cols'); for ( var i = 0; null ...

  8. 高效团队的gitlab flow最佳实践

    当前git是大部分开发团队的首选版本管理工具,一个好的流程规范可以让大家有效地合作,像流水线一样有条不紊地进行团队协作. 业界包含三种flow: Git flow Github flow Gitlab ...

  9. Redis 实战 —— 13. 扩展 Redis

    简介 当数据量增大或者读写请求增多后,一台 Redis 服务器可能没办法再存储所有数据或者处理所有读写请求,那么就需要对 Redis 进行扩展,保证 Redis 在能存储所有数据对情况下,同时能正常处 ...

  10. cassandra权威指南读书笔记--Cassandra架构(3)

    分阶段事件驱动架构 SEDASEDA(Staged Event-Driven Architecture)的核心思想是把一个请求处理过程分成几个Stage,不同资源消耗的Stage使用不同数量的线程来处 ...