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
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 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.
The line contains M integer, the i-th integer is the answer shows above when d is the i-th number.
3 3 3 3 3 3 3 5 3 1 2 3
7 1 0
59 3 0 1 1
老套路了。。。
设 f(d) 为 gcd 为 d 的数对的对数,F(d)为gcd是d的倍数的数对的对数,
那么此处F(d)如何计算:
我们设数组 a[ i ] 的 n 个数中,是 d (就是条件二要求的那个 gcd)的倍数的有 sum 个,那么不是 d 的倍数的有 n-sum 个
那么这 n - sum 个 a[ i ] 是绝对要使得 b[ i ] ! = a[ i ] 的
然后还剩下 sum 个 a[ i ] ,我们可以从中选择 k - (n - sum)个 a[ i ] 使得 b[ i ] ! = a[ i ],然后其余的 a[ i ] 都要使得 a[ i ] = b[ i ]
所以 F(d)= C(sum , k-( n - sum) )*pow( [ m/d ] , n-sum )*pow( [ m/d ] - 1 , k - ( n - sum ) ) ([ m / d ] 向下取整)
至于为什么要减一。。。那 n - sum 个 a[ i ] 因为不是 d 的倍数,所以不会包含在 [ m / d ]*d 里面,在这里面选择 b[ i ] 的时候就不用减一了
另外 sum 个 a[ i ] 是 d 的倍数,所以会包含在 [ m / d ]*d 里面,所以在里面选择 b[ i ] 使得 b[ i ] ! = a[ i ] 的时候要减一。
然后就函数求和加加减减
下面代码中 sum[ i ] 表示 i 的倍数有多少个
这个题由于求 F(d)的形式比较特殊,所以没法分段求和来加一波速(大概?)
不过暴力能过
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;
typedef long long LL;
const LL MOD=1e9+7;
#define fi first
#define se second
const int MAXN=500000+23;
LL prime[MAXN],total,miu[MAXN];
bool isprime[MAXN];
void make()
{
int m=MAXN-3;
memset(isprime,true,sizeof(isprime));
total=0;
isprime[0]=isprime[1]=false;
miu[1]=1;
for(int i=2;i<=m;i++)
{
if(isprime[i]){prime[++total]=i;miu[i]=-1;}
for(int j=1;j<=total&&prime[j]*i<=m;j++)
{
isprime[i*prime[j]]=false;
if(i%prime[j])
{
miu[i*prime[j]]=-miu[i];
}
else
{
miu[i*prime[j]]=0;
break;
}
}
}
miu[0]=0;
// for(int i=1;i<=m;i++)miu[i]+=miu[i-1];
}
LL n,m,k;
LL jc[MAXN];
LL quick(LL x,LL a)
{
LL res=1;
while(a)
{
if(a&1)res=res*x%MOD;
x=x*x%MOD;
a>>=1;
}
return res%MOD;
}
LL C(LL a,LL b)
{
if(b==a||b==0)return 1;
LL r1=jc[a],r2=jc[b]*jc[a-b]%MOD;
r2=quick(r2,MOD-2);
return r1*r2%MOD;
}
LL a[MAXN],sum[MAXN],F[MAXN];
LL vis[MAXN];
int main()
{
make();
jc[0]=1;
for(int i=1;i<=MAXN-100;i++)
{
jc[i]=jc[i-1]*i%MOD;
}
while(scanf("%lld%lld%lld",&n,&m,&k)!=-1)
{
memset(sum,0,sizeof(sum));
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++)scanf("%lld",&a[i]),vis[a[i]]++;
//sum[1]=n;
for(LL i=1;i<=m;i++)
{
for(LL j=i;j<=m;j+=i)
{
if(vis[j])sum[i]+=vis[j];
}
}
for(LL i=1;i<=m;i++)
{
LL ans=0;
LL b=n-sum[i];
LL z=m/i;
if(b<=k)
{
F[i]=(quick(z,b)*quick(z-1,k-b)%MOD)*C(sum[i],k-b)%MOD;
}
else
{
F[i]=0;
}
}
for(int i=1;i<=m;i++)
{
LL ans=0;
if(F[i]==0)ans=0;
else for(int j=i;j<=m;j+=i)
{
ans+=miu[j/i]*F[j];
ans%=MOD;
}
printf("%lld",(ans+MOD)%MOD);
if(i<m)putchar(' ');
}
puts("");
}
return 0;
}
emmmmm。。。。。。。大概就这样了吧
本人蒟蒻,如有错误,还望指出