Description
青青草原上有\(k\)只羊,他们聚集在包包大人的家里,举办一年一度的表彰大会,在这次的表彰大会中,包包大人让羊们按自己的贡献从小到大排成一排,以便于发放奖金。
每只羊都会得到数值在\(1\)~\(n\)的奖金,并且第i只羊的奖金应为第\(i+1\)只羊的约数(即满足\(ai|ai+1\))。
现在包包大人想知道一共有多少种不同的发放奖金的方式(两种发放奖金的方式不同是指在两种发放奖金的方式中存在某只羊拿到的奖金不同)
Input
一行两个正整数\(n\),\(k\),满足(\(1<=n\),\(k<=1000000\))
Output
一行一个整数代表发放奖金的方案对\(1000000007\)取模的结果
Sample Input
6 4
Sample Output
3 9
Data Constraint
对于\(20\)%的数据:\(n,k<=10\)
对于\(50\)%的数据:\(n,k<=2000\)
对于\(100\)%的数据:\(n,k<=1000000\)
Limit
\(2000ms\) \(512M\)
Solution
不妨设第\(i\)只羊获得的奖金为\(ai\),那么\(a\)序列中不同的数的个数不超过\(O(logn)\),且所有数字按升序排列,因此可以枚举\(a\)序列中不同的数的个数\(d\),不妨假设这些不同的数分别为\(p1\),\(p2\),\(p3\)...\(pd\),考虑统计\(p\)序列的个数: 用\(f[i][j]\)表示长度为\(i\)且\(pi=j\)的\(p\)序列个数,用\(f[i+1][t*j]+=f[i][j]\)来更新即可。
那么\(cnt[i]=\sum f[i][j]\)即为长为\(i\)的\(p\)序列个数。
接下来考虑求出\(p1\),\(p2\),\(p3\)...\(pd\)放入\(a\)序列中的方案数,用隔板法可以求出这个方案数为\(C(k-1,d-1)\),因而总的方案数为
\(\sum^{logk}_{i=1}cnt[d]\ast C(k-1,d-1)\)
Code
#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
#define MOD 1000000007
#define N 1000020
#define M 22
#define MAXN 10010
ll n, k, ans;
ll H[N], f[M][N], cnt[M];
inline ll read() {
ll s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
inline ll Pow(ll a, ll k) {
ll ans = 1;
while (k) {
if (k & 1) (ans *= a) %= MOD;
(a *= a) %= MOD;
k >>= 1;
}
return ans;
}
inline ll Inv(int a) {
return Pow(a, MOD - 2);
}
inline void Init() {
H[0] = 1;
for (register int i = 1; i <= N; i++)
H[i] = (H[i - 1] * i) % MOD;
}
inline ll C(ll x, ll y) {
return H[x] * Inv(H[y]) % MOD * Inv(H[x - y]) % MOD;
}
int main() {
freopen("commend.in", "r", stdin);
freopen("commend.out", "w", stdout);
Init();
n = read(), k = read();
for (register int i = 1; i <= n; i++)
f[1][i] = 1;
for (register int i = 1; i < M - 1; i++)
for (register int j = 1; j <= n; j++)
for (register int k = j + j; k <= n; k += j)
(f[i + 1][k] += f[i][j]) %= MOD;
for (register int i = 1; i < M; i++)
for (register int j = 1; j <= n; j++)
(cnt[i] += f[i][j]) %= MOD;
for (register int i = 1; i <= k && i < M; i++)
(ans += cnt[i] * C(k - 1, i - 1) % MOD) %= MOD;
cout << ans;
return 0;
}
原文地址:https://www.cnblogs.com/Agakiss/p/11779203.html