[关闭]
@ljt12138 2017-05-31T15:37:47.000000Z 字数 2054 阅读 877

一道狄利克雷卷积模板题的组合做法


题目描述:

给定上的取值,求函数:

上的取值。

狄利克雷卷积做法

容易发现,,直接用狄利克雷卷积快速幂即可。

组合做法

显然,的所有因子在整除关系下构成一个偏序,可以等价地转化为一张带自环而无其他环的图。则从开始的序列与有向无环图上从开始长度为的路径一一对应。

考虑求从开始长度为的路径所有终点位置的和,容易写出方程:

然而这个dp的状态规模是的,考虑原因:存在很长的链是因为可以多次在一个数上重复(即在自环上走)。设为长度为从开始长度为的所有不经过自环的终点位置的和,则:

显然,现在向路径上插入自环。考虑的贡献,。需要在个位置上插入个自环,用隔板法分析可知为:,因此:

而答案等于的所有因子的的和,即:

自此问题得以解决。复杂度

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 100005;
  4. struct node {
  5. int to, next;
  6. } edge[MAXN*20];
  7. int head[MAXN], top = 0;
  8. inline void push(int i, int j)
  9. { edge[++top] = (node){j, head[i]}, head[i] = top; }
  10. int n, k;
  11. void init()
  12. {
  13. for (register int i = 1; i <= 100000; i++)
  14. for (register int j = 2; j*i <= 100000; j++)
  15. push(j*i, i);
  16. }
  17. long long f[MAXN][20], a[MAXN];
  18. const long long mod = 1000000007ll;
  19. long long fac[MAXN], inv[MAXN], g[MAXN], g2[MAXN];
  20. long long power(int a, long long n)
  21. {
  22. if (n == 0) return 1;
  23. long long b = a, ans = 1;
  24. for (int k = 0; k <= 30; k++) {
  25. if (n&(1ll<<k)) (ans *= b) %= mod;
  26. (b *= b) %= mod;
  27. }
  28. return ans;
  29. }
  30. inline long long choose(int K, int k)
  31. { return fac[K]*inv[k]%mod*inv[K-k]%mod; }
  32. void init_c()
  33. {
  34. inv[0] = 1;
  35. for (int i = 1; i <= 100000; i++) inv[i] = (inv[i-1]*power(i, mod-2))%mod;
  36. fac[0] = 1;
  37. for (int i = 1; i <= 100000; i++) (fac[i] = fac[i-1]*i) %= mod;
  38. }
  39. void dp()
  40. {
  41. scanf("%d%d", &n, &k);
  42. for (int i = 1; i <= n; i++) scanf("%lld", &f[i][1]);
  43. for (int j = 2; j <= 17; j++)
  44. for (register int i = 1; i <= n; i++) {
  45. f[i][j] = 0;
  46. for (register int k = head[i]; k; k = edge[k].next) {
  47. int to = edge[k].to;
  48. (f[i][j] += f[to][j-1]) %= mod;
  49. }
  50. }
  51. for (register int i = 1; i <= n; i++) {
  52. long long ans = 0;
  53. for (register int j = 1; j <= 17; j++)
  54. (ans += f[i][j]*choose(k-1, j-1)%mod) %= mod;
  55. g[i] = ans;
  56. }// cerr << endl;
  57. memset(g2, 0, sizeof g2);
  58. for (register int i = 1; i <= n; i++)
  59. for (register int j = 1; j*i <= n; j++)
  60. (g2[j*i] += g[i]) %= mod;
  61. for (int i = 1; i <= n; i++)
  62. printf("%lld ", g2[i]);
  63. puts("");
  64. }
  65. int main()
  66. {
  67. freopen("b.in", "r" , stdin);
  68. freopen("b.out", "w", stdout);
  69. init();
  70. init_c();
  71. int T; scanf("%d", &T);
  72. while (T--) dp();
  73. return 0;
  74. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注