Alice is playing a game with Bob.
Alice shows N integers a 1, a 2, …, a N, and M, K. She says each integers 1 ≤ a i ≤ M.
And now Alice wants to ask for each d = 1 to M, how many different sequences b 1, b 2, …, b N. which satisfies :
1. For each i = 1…N, 1 ≤ b[i] ≤ M
2. gcd(b 1, b 2, …, b N) = d
3. There will be exactly K position i that ai != bi (1 ≤ i ≤ n)
Alice thinks that the answer will be too large. In order not to annoy Bob, she only wants to know the answer modulo 1000000007.Bob can not solve the problem. Now he asks you for HELP!
Notes: gcd(x 1, x 2, …, x n) is the greatest common divisor of x 1, x 2, …, x n
Input
The input contains several test cases, terminated by EOF.
The first line of each test contains three integers N, M, K. (1 ≤ N, M ≤ 300000, 1 ≤ K ≤ N)
The second line contains N integers: a 1, a 2, …, a n (1 ≤ a i ≤ M) which is original sequence.
Output
For each test contains 1 lines :
The line contains M integer, the i-th integer is the answer shows above when d is the i-th number.
Sample Input
3 3 3
3 3 3
3 5 3
1 2 3
Sample Output
7 1 0
59 3 0 1 1
Hint
In the first test case :
when d = 1, {b} can be :
(1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 2, 2)
(2, 1, 1)
(2, 1, 2)
(2, 2, 1)
when d = 2, {b} can be :
(2, 2, 2)
And because {b} must have exactly K number(s) different from {a}, so {b} can't be (3, 3, 3), so Answer = 0
给你一个数数组 a[i],其中给出的每一个数字和要求的数字都是属于[1,m],现在问你根据a[] a [ i ] , 其 中 给 出 的 每 一 个 数 字 和 要 求 的 数 字 都 是 属 于 [ 1 , m ] , 现 在 问 你 根 据 a [ ] 构造一个 b[],且a和b中间的不相等的元素的个数恰好有k b [ ] , 且 a 和 b 中 间 的 不 相 等 的 元 素 的 个 数 恰 好 有 k 个。
现在问你 gcd(b[])分别为1,2,……,m的个数分别有多少种可能情况 g c d ( b [ ] ) 分 别 为 1 , 2 , … … , m 的 个 数 分 别 有 多 少 种 可 能 情 况 。
通过以往的做题经验我们知道,对于求一个范围内含有确定的因数 d d 的个数并不好求,但是好求的是一个范围内含有因数 d及其倍数的数字的数量即总数除以d d 及 其 倍 数 的 数 字 的 数 量 即 总 数 除 以 d
那么对于这道题我们思路可以从大到小枚举m假设枚举的数是 i,我们首先可以求出m i , 我 们 首 先 可 以 求 出 m 范围内有多少个数因子含有 i及其i的倍数及为num=mi(m i 及 其 i 的 倍 数 及 为 n u m = m i ( m 范围内只有这么多,这是全部)
那么实际给定的 a a 数列中有多少是满足这个条件的数呢?
我们输入时完全可以记录每个数的个数(因为 a数列每个数并不大),这样我们只需从i每次以i a 数 列 每 个 数 并 不 大 ) , 这 样 我 们 只 需 从 i 每 次 以 i 为步长统计出 a数列中的含有i及其i的倍数作为因子的数的个数及为cur a 数 列 中 的 含 有 i 及 其 i 的 倍 数 作 为 因 子 的 数 的 个 数 及 为 c u r
那么总数 n减去这个个数剩下的就是a n 减 去 这 个 个 数 剩 下 的 就 是 a 数列中不满足条件的数的个数即 n−cur n − c u r
这个时候我们就需要判断,因为我们只能确定的修改k个值,那么这时就分了三种情况
说明剩下的需要修改的数大于 k个才能保证每个数含有因子是为i及其i的倍数从而保证gcd=i k 个 才 能 保 证 每 个 数 含 有 因 子 是 为 i 及 其 i 的 倍 数 从 而 保 证 g c d = i ,而题目要求我们只能该k个那么在这种情况下将没有符合条件的 b b 数列,因而答案为0。
此时说明剩下的数恰好k个那么我们直接修改即可了根据上面我们知道共有 num=mi n u m = m i 种选择,共有k个需要选因此共有 numn−cur=numk n u m n − c u r = n u m k 种
3) n−cur<k: n − c u r < k :
说明剩下的 a数列中不满足条件的数的个数小于k个,而我们又必须要该k a 数 列 中 不 满 足 条 件 的 数 的 个 数 小 于 k 个 , 而 我 们 又 必 须 要 该 k 个,因此我们只能再从已将满足条件的数中再修改 cur+k−n c u r + k − n 个,因此这 cur+k−n c u r + k − n 需要从满足条件的 cur c u r 中选,此时便需要用到组合数 Ccur+k−ncur C c u r c u r + k − n 中,而每个我们可以替换的数是 num中除去a n u m 中 除 去 a 中原来那个数本身,因此每个位置还有 num−1 n u m − 1 种选择即 (num−1)cur+k−n ( n u m − 1 ) c u r + k − n ,所以这种情况下我们除了需要把 n−cur n − c u r 个不满足条件的位置修改,该需要把 cur+k−n c u r + k − n 个已经满足条件的修改以凑够修改k个数
因此答案为情况2和情况3的组合即为
综上我们就求得了 b数组的gcd为i即i b 数 组 的 g c d 为 i 即 i 的倍数的所有可能情况
我们当然不想要 gcd为i的倍数的情况,因此需要减去,这时就体现出了m g c d 为 i 的 倍 数 的 情 况 , 因 此 需 要 减 去 , 这 时 就 体 现 出 了 m 从大到小枚举的好处,我们发现当我们求 得i是i 得 i 是 i 的倍数的情况已经求出来了,因此我们只需要在遍历一遍i的倍数的答案之间减去即可。
code:
#include
using namespace std;
const int maxn = 300003;
const int mod = 1e9+7;
typedef long long ll;
int a[maxn],f[maxn],n,m,k,ai,tep;
ll P[maxn],Q[maxn];
ll q_pow(ll a,ll b){
ll ans = 1;
while(b){
if(b & 1)
ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
ll C(ll x,ll y){
if(y == 0 || x == y) return 1;
ll ans = P[x] * Q[y] % mod;
ans = ans * Q[x-y] % mod;
return ans;
}
int main(){
ll cur,tot,num;
Q[1] = P[0] = 1;
for(int i = 1; i < maxn; i++){
P[i] = (P[i-1] * i) % mod;
Q[i] = q_pow(P[i],mod-2);
}
while(scanf("%d%d%d",&n,&m,&k) != EOF){
for(int i = 1; i <= m; i++) a[i] = f[i] = 0;
for(int i = 1; i <= n; i++){
scanf("%d",&ai);
a[ai]++;
}
for(int i = m; i > 0; i--){
cur = 0;
tot = 1;
num = m / i;
for(int j = i; j <= m; j += i) cur += a[j];
if(n - cur > k){
f[i] = 0;
continue;
}
tot = q_pow(num,n-cur);
if(n - cur != k){
tep = C(cur,k+cur-n) * q_pow(num-1,k+cur-n) % mod;
tot = tot * tep % mod;
}
f[i] = tot;
for(int j = i + i; j <= m; j += i){
f[i] -= f[j];
if(f[i] < 0) f[i] += mod;
}
}
printf("%d",f[1]);
for(int i = 2; i <= m; i++){
printf(" %d",f[i]);
}
printf("\n");
}
return 0;
}
实际上经过上面的分析我们发现,上面我们说的三种情况实际上都可以用第三种情况表示即
这个公式可以完整的表示三种情况
而且这是求的gcd = i的倍数的个数
由此我们想到了莫比乌斯反演
此时的
所以
只要预处理 数F(d) 数 F ( d ) ,然后直接求和累加即可,代码就不再写了,只说一下莫比乌斯反演的思路