【数位DP】【P4317】花神的数论题

【数位DP】【P4317】花神的数论题

Description

给定 n,求 n 以内所有正整数二进制下 1 的个数的乘积,答案对 107+7 取模

Limitations

1n1015

Solution

这是我见过最简单的数位 DP,然而我还是翻车了……

考虑 1 最多有 O(logn) 个,因此 1 的个数是可以枚举的。

枚举求有 k1 的数的个数,设 fi,j 是考虑前 i 位,剩下的位置还需要填 j1 且不顶上界的方案数。转移显然:

fi,j=fi1,j+1fi1,j

分别对应第 i 位填 0 和填 1

顶上界的情况记一下已经有几个 1 就可以更新了。

因为只考虑 1 的个数,所以前导 0 对答案没有贡献,不需要做特殊处理。

需要注意的是,107+7 并不是一个质数,107+7 = 941×10627,因此在 DP 的时候并不能模 p1,因为他的欧拉函数并不是减一简单。事实上并不需要取模,因为方案数不会超过 n,因此直接计算即可。

Code

#include <cstdio>
#include <cstring>

const int maxn = 64;
const int MOD = 10000007;

ll n;
int cnt, upc = -1;
ll ans = 1;
ll frog[maxn][maxn];
int MU[maxn];

ll calc(const int x);
ll mpow(const int x, ll y);

int main() {
  freopen("1.in", "r", stdin);
  qr(n);
  do cnt += (MU[++upc] = n & 1); while (n >>= 1);
  for (int i = 1; i < 60; ++i) {
    ans = ans * mpow(i, calc(i)) % MOD;
  }
  ans = ans * cnt % MOD;
  qw(ans, '\n', true);
  return 0;
}

ll calc(const int x) {
  int cnt = x - 1;
  memset(frog, 0, sizeof frog);
  frog[upc][x] = 1;
  for (int i = upc - 1; ~i; --i) {
    int di = i + 1;
    for (int j = 0; j <= x; ++j) {
      frog[i][j] = frog[di][j + 1] + frog[di][j];
    }
    if (MU[i] && ~cnt) {
      ++frog[i][cnt--];
    }
  }
  return frog[0][0];
}

ll mpow(const int x, ll y) {
  ll _ret = 1, _tmp = x;
  while (y) {
    if (y & 1) {
      _ret = _ret * _tmp % MOD;
    }
    _tmp = _tmp * _tmp % MOD;
    y >>= 1;
  }
  return _ret;
}

Summary

神tm 107+7 竟然不是个质数

posted @   一扶苏一  阅读(212)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示