i i" />

[BZOJ3131][Sdoi2013]淘金(數位DP+貪心+堆)


反過來想:對於一個 i ,求有多少個 j 滿足 f ( j ) = i (下面記作 c ( i ) )。
可以發現在 f ( j ) = i 中,數 i 必然可以分解成 2 a × 3 b × 5 c × 7 d 的形式。
所以雖然 N 10 12 ,但是滿足 c ( i ) > 0 i 是不多的(實測最多 14672 個)。
因此設狀態: d p [ i , j , 0 / 1 ] 表示從低到高位到了第 i 位,各位數的積為 j (需要離散化),第三維表示小於等於/大於 N 的從低到高前 i 位。
轉移即枚舉第 i 位數 k ,如果 k | j
那么 d p [ i , j , 0 / 1 ] 可以從 d p [ i 1 , j k , 0 / 1 ] 轉移過來。
這樣就能算出所有 > 0 c ( i )
回到題目,可以得出,位置 ( x , y ) 的金子數目為 c ( x ) × c ( y )
所以要求的就是 c ( x ) × c ( y ) 的前 K 大值之和。
由於 K 較小,因此可以將 c 從小到大排序,用大根堆維護 t (有效的 c ( x ) 的個數)個指針(如果第 i 個指針在 j 位置,則關鍵字為 c ( i ) × c ( j ) ,這里的 c 是排序后的,因此 c ( i ) 在這里是指排序后第 i 小的 c 值),每次貪心選擇關鍵字最大的指針向左移,統計答案。
代碼:

#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
using namespace std;
typedef long long ll;
const int N = 15, M = 15000, MX = 1e9 + 7;
ll n, otz[M], f[N][M][2], sum[M];
int K, QAQ, a[N], ans;
map<ll, int> orz;
struct cyx
{
    int id, pos;
    cyx() {}
    cyx(int _x, int _y) :
        id(_x), pos(_y) {}
    friend inline bool operator < (cyx a, cyx b)
    {
        return sum[a.id] * sum[a.pos] < sum[b.id] * sum[b.pos];
    }
};
priority_queue<cyx> pq;
void DP(ll num)
{
    int i, j, k, n = 0;
    while (num) a[++n] = num % 10, num /= 10;
    For (k, 1, 9)
        f[1][orz[k]][k > a[1]]++;
    For (i, 2, n) For (j, 1, QAQ) For (k, 1, 9)
    {
        ll q = otz[j]; if (q % k != 0) continue;
        int h = orz[q / k];
        if (k < a[i]) f[i][j][0] += f[i - 1][h][0] + f[i - 1][h][1];
        else if (k > a[i])
            f[i][j][1] += f[i - 1][h][0] + f[i - 1][h][1];
        else f[i][j][0] += f[i - 1][h][0],
            f[i][j][1] += f[i - 1][h][1];
    }
    For (j, 1, QAQ) For (i, 1, n)
        sum[j] += f[i][j][0] + (i == n ? 0 : f[i][j][1]);
    sort(sum + 1, sum + QAQ + 1);
    K = min(1ll * K, 1ll * QAQ * QAQ);
}
int main()
{
    int i, j, k, h;
    ll x = 1;
    cin >> n >> K;
    For (i, 0, 39)
    {
        ll t = x;
        For (j, 0, 25)
        {
            ll r = x;
            For (k, 0, 17)
            {
                ll w = x;
                For (h, 0, 14)
                {
                    otz[orz[x] = ++QAQ] = x;
                    x *= 7;
                    if (x > n) break;
                }
                x = w * 5;
                if (x > n) break;
            }
            x = r * 3;
            if (x > n) break;
        }
        x = t * 2;
        if (x > n) break;
    }
    DP(n);
    For (i, 1, QAQ) pq.push(cyx(i, QAQ));
    For (i, 1, K)
    {
        cyx u = pq.top(); pq.pop();
        ans = (ans + sum[u.id] * sum[u.pos] % MX) % MX;
        if (u.pos == 1) continue;
        pq.push(cyx(u.id, u.pos - 1));
    }
    cout << ans << endl;
    return 0;
}

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com