简要题意:
求在 个数中选 个数使其 分别为 ~ 的个数。 .
这是某洛谷月赛的 ,有一定思维难度。
子任务
子任务 : , ,
暴力枚举 个数记录 即可。
时间复杂度: .
实际得分: .
子任务
子任务 : .
给一些简单 乱搞的部分分。
子任务
子任务 : , , .
预处理两两 . 但不是 的那种,而是预处理所有 的数的个数记为 ,在 上两两匹配 记录个数即可。
时间复杂度: .
实际得分: .
子任务
子任务 : ,
这是个送分的子任务,统计每个数出现的次数即可。
时间复杂度: .
实际得分: .
子任务
子任务 : , .
似乎不能暴力统计两两 了。所以这个子任务想要解决必须写正解,如果你会乱搞可以试一试。
子任务 ~
对于 的数据, , .
我们需要考虑高级的 方式。
用 表示选出 个数,其 为 的倍数 的个数。这里我们要考虑容斥,不是很简单的样子。
因为在所有是 的倍数中选 个用组合,但是不完全正确,因为 很有能计算重复,所以我们用 容斥 计算,把所有的 全部减掉,然后对它们的和进行组合。
如何计算组合呢?我们可以预处理 阶乘逆元 然后 回答。
时间复杂度: .
实际得分: .
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD=1e9+7;
const int N=1e6+1;
inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
ll f[N],inv[N],invf[N];
ll g[N]; int t[N],n,m,k;
inline ll calc(int x,int y) {
return x<y?0:(f[x]*invf[y]%MOD*invf[x-y]%MOD);
} //组合
int main(){
n=read(),m=read(),k=read();
f[0]=invf[0]=1;
for(int i=1;i<=n;i++) {
inv[i]=(i==1)?1:(inv[MOD%i]*(MOD-MOD/i)%MOD);
f[i]=f[i-1]*i%MOD; invf[i]=invf[i-1]*inv[i]%MOD; //处理逆元,阶乘逆元
t[read()]++; //记录桶
} for(int i=m;i;i--) {
int cnt=0; //记录和
for(int j=1;i*j<=m;j++) cnt+=t[i*j],g[i]=(g[i]-g[i*j]+MOD)%MOD; //容斥减掉 , 统计和
g[i]=((g[i]+calc(cnt,k))%MOD+MOD)%MOD; //和的组合
} for(int i=1;i<=m;i++) printf("%lld ",g[i]);
return 0;
}