DP(数位专题六)

23 篇文章 0 订阅
11 篇文章 0 订阅

题意: 给定右端点r , 求

∏ i = 1 i ≤ r s u m ( i ) \prod _{i = 1}^{i\leq r}sum(i) i=1irsum(i)

  • sum(i)代表,i在二进制表示下有多少个1
  • s u m ( i ) = _ _ b u i l t i n _ _ p o p c o u n t ( i ) sum(i)=\_\_builtin\_\_popcount(i) sum(i)=__builtin__popcount(i)

>> face <<

Strategy: 刚拿到这题的时候一点思路也没有 我们这样想: sum(i) == 1 的有多少个, sum(i) == 2的 有多少个 那么答案就是

∏ i = 1 i ≤ c n t i j \prod _{i = 1}^{i \leq cnt} i^{j} i=1icntij

  • i j → s u m ( n u m ) = = i 的 数 出 现 了 j 次 i^j\to sum(num) == i的数出现了j次 ijsum(num)==ij

状态: d p [ i ] [ k ] [ j ] → dp[i][k][j]\to dp[i][k][j]二进制下搜到第i位,能填多少个1, 目前填了j个1状态

目标: ( s u m [ r ] ) ( s u m [ i ] 代 表 1   i 内 的 所 有 合 法 数 的 个 数 ) (sum[r])(sum[i]代表1~i内的所有合法数的个数) (sum[r])(sum[i]1 i)

边界: 本题无

合法判断: 条件转移合法判断

记忆化转移无需预处理

attention: 状态的唯一性

双倍经验: 记忆化细节少

@author: jasonleft 记忆化数位
#include <bits/stdc++.h>
#include <bits/extc++.h>
#define _rep(i, a, b) for (ll i = (a); i <= (b); ++i)
#define _rev(i, a, b) for (ll i = (a); i >= (b); --i)
#define _for(i, a, b) for (ll i = (a); i < (b); ++i)
#define _rof(i, a, b) for (ll i = (a); i > (b); --i)
#define ll long long
#define db double
#define oo 0x3f3f3f3f
#define eps 0.00001
#define all(x) x.begin(), x.end()
#define met(a, b) memset(a, b, sizeof(a))
#define id(x) ((x + 8))
#define bin(x) cerr << #x << " is " << bitset<8>(x) << endl
#define what_is(x) cerr << #x << " is " << x << endl
#define lowbit(x) x &(-x)
using namespace std;
const ll maxn = 55;
const ll mod = 10000007;
ll dp[maxn][maxn][maxn], r, a[maxn], cnt;
inline ll qpow(ll a, ll b)

{
    ll ans = 1;
    for (; b; b >>= 1, a = a * a % mod)
    {
        if (b & 1)
            ans = a * ans % mod;
    }
    return ans;
}
ll dfs(ll cur, ll left, ll used, bool up)
{
    if (cur == 0)
        return used == left;
    ll &t = dp[cur][left][used];
    if (!up && ~t)
        return t;
    ll ans = 0;
    _rep(i, 0, 1)
    {
        if (!up || i <= a[cur])
        {
            ans += dfs(cur - 1, left, used + (i == 1), up && i == a[cur]);
        }
    }
    if (!up)
        t = ans;
    return ans;
}
ll __ask(ll __)
{
    while (__)
        a[++cnt] = __ & 1, __ >>= 1;
    ll ans = 1;
    _rep(i, 2, cnt)
    {
        ans = (ans * qpow(i, dfs(cnt, i, 0, i))) % mod;
    }
    return ans;
}
signed main()
{

    ios::sync_with_stdio(0);
    met(dp, -1);

    cin >> r;
    cout << __ask(r) << endl;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值