题解(5031. 【NOI2017模拟3.27】B)(数论,组合数学)
题目:
n,k<=1e5;
官方题解写的好像是狄利克雷卷积快速幂,可惜太菜了没看出来.
考场想了个比较奇特的方法,考虑枚举ik,即对于每个f(ik)考虑它被计算了多少次
因为ik一定是i的约数,所以可以考虑枚举i的约数
于是问题就被转化为最后一个数给定,前面每个数都是后一个数的倍数的序列有多少个,设对于x有dp(x),把k当做常数
乍一看很不可做,但如果对一个数质因数分解,我们可以用到倍数的性质,一个数x是另一个数y的倍数,当且仅当每个质因子的指数都满足(cx >= cy)
所以不妨令t = i / ik, 对t质因数分解,设t = ∏pici ,则dp(ik) = ∏C(ci+k,ci),为什么呢?因为既然质因子要满足单调不减,我们就可以把质因子的序列当做无序,因为只要种类和个数相同,排序成单调不减就相同
于是变成k个无差别小球扔进(ci + 1)(指数可以是0)个不同的盒子,允许有空,隔板法插一插
时间复杂度记忆化一下大概就是O(n*sqrt(n/logn))(除以一个log是因为我线性筛预处理了质数);
(多测不清空,暴零两行泪)
代码如下
/*B*/
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
const int maxn = 2e5 + 10;
const int mod = 1e9 + 7;
int f[maxn],g[maxn];
int jc[maxn],invjc[maxn];
vector<int>pr[maxn];
int dp[maxn];
int prime[maxn],v[maxn],m;
int qpow(int x,int y){
int ans = 1;
while(y){
if(y & 1) ans = 1ll * ans * x % mod;
x = 1ll * x * x % mod;
y >>= 1;
}
return ans;
}
int read(){
char c = getchar();
int x = 0;
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48,c = getchar();
return x;
}
void Shpi(int n){
for(int i = 2; i <= n; ++i){
if(!v[i]){
v[i] = i;
prime[++m] = i;
}
for(int j = 1; j <= m; ++j){
if(v[i] < prime[j] || i * prime[j] > n) break;
v[i * prime[j]] = prime[j];
}
}
}
int C(int x,int y){
return 1ll * jc[x] * invjc[y] % mod * invjc[x - y] % mod;
}
int sol(int x,int k){
if(dp[x] != -1) return dp[x];
int idx = x;
dp[idx] = 1;
int i;
for(i = 1; i <= m; ++i){
int v = prime[i];
int cnt = 0;
if(v * v > x) break;
while(x % v == 0){
cnt++;
x /= v;
}
dp[idx] = 1ll * dp[idx] * C(cnt+k,cnt) % mod;
}
if(x != 1)
dp[idx] = 1ll * dp[idx] * C(k+1,1) % mod;
return dp[idx];
}
int main(){
freopen("b.in","r",stdin);
freopen("b.out","w",stdout);
jc[0] = 1;
Shpi(1e5);
for(int i = 1; i <= 1e5; ++i)
jc[i] = 1ll * jc[i-1] * i % mod;
invjc[100000] = qpow(jc[100000],mod-2);
for(int i = 1e5 - 1; i >= 0; i--)
invjc[i] = 1ll * invjc[i+1] * (i + 1) % mod;
for(int i = 1; i <= 1e5; ++i){
for(int j = 1; j * i <= 1e5; ++j)
pr[i * j].push_back(i);
}
int t = read();
while(t--){
int n = read(),k = read();
memset(dp,-1,sizeof(dp));
for(int i = 1; i <= n; ++i) f[i] = read();
for(int i = 1; i <= n; ++i){
g[i] = 0;
for(int j = 0; j < (int)pr[i].size(); ++j){
int x = pr[i][j];
g[i] = (1ll * f[x] * sol(i/x,k-1) + g[i]) % mod;
}
}
for(int i = 1; i <= n; ++i)
printf("%d ",g[i]);
puts("");
}
return 0;
}

浙公网安备 33010602011771号