zoukankan      html  css  js  c++  java
  • BZOJ2757

    题目

    小Z在玩一个叫做《淘金者》的游戏。游戏的世界是一个二维坐标。X轴、Y轴坐标范围均为1..N。初始的时候,所有的整数坐标点上均有一块金子,共N*N块。
    一阵风吹过,金子的位置发生了一些变化。细心的小Z发现,初始在(i,j)坐标处的金子会变到(f(i),f(j))坐标处。其中f(x)表示x各位数字的乘积,例如f(99)=81,f(12)=2,f(10)=0。如果金子变化后的坐标不在1..N的范围内,我们认为这块金子已经被移出游戏。同时可以发现,对于变化之后的游戏局面,某些坐标上的金子数量可能不止一块,而另外一些坐标上可能已经没有金子。这次变化之后,游戏将不会再对金子的位置和数量进行改变,玩家可以开始进行采集工作。
    小Z很懒,打算只进行K次采集。每次采集可以得到某一个坐标上的所有金子,采集之后,该坐标上的金子数变为0。
    现在小Z希望知道,对于变化之后的游戏局面,在采集次数为K的前提下,最多可以采集到多少块金子?
    答案可能很大,小Z希望得到对1000000007(10^9+7)取模之后的答案。

    题解

    这里两个坐标是互相独立的,主要求出一维的情况,二维的答案就是相乘的结果。(牛客2020多校有道数位dp就是两个互相关联的数之间的数位dp)。

    突破口在于f的值域大于0的情况非常少,题目范围下只有不到1万个数。所以可以先预处理出这些数,然后离散一下。分别求出每个乘积是多少个数的乘积(该位置下有多少金块),假设位cnt数组。

    最后问题转变成求两个有序cnt数组,分别取出一个数相乘的前k大个数。把这排序后看成k个有序序列,然后优先队列多路归并取前k个数即可。

    #include <bits/stdc++.h>
    
    #define endl '
    '
    #define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
    #define FILE freopen(".//data_generator//in.txt","r",stdin),freopen("res.txt","w",stdout)
    #define FI freopen(".//data_generator//in.txt","r",stdin)
    #define FO freopen("res.txt","w",stdout)
    #define pb push_back
    #define mp make_pair
    #define seteps(N) fixed << setprecision(N) 
    typedef long long ll;
    
    using namespace std;
    /*-----------------------------------------------------------------*/
    
    ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    #define INF 0x3f3f3f3f
    
    const int N = 1e5 + 10;
    const int M = 1e9 + 7;
    const double eps = 1e-5;
    
    set<ll> num[2][10];
    vector<ll> pd;
    ll f[20][N];
    ll cnt[N];
    bool vis[20][N];
    int di[N];
    
    int get(ll v) {
        int p = lower_bound(pd.begin(), pd.end(), v) - pd.begin() + 1;
        assert(pd[p - 1] == v);
        return p;
    }
    
    ll dfs(int p, ll st, int lmt, int lead) {
        if(!p) {
            return (!lead) && (st == 1);
        }
        if(!lead && !lmt && f[p][get(st)] >= 0) return f[p][get(st)];
        ll res = 0;
        int maxx = lmt ? di[p] : 9;
        for(int i = 0; i <= maxx; i++) {
            if(lead) {
                if(!i) res += dfs(p - 1, st, lmt && i == maxx, i == 0 && lead);
                else if(st % i == 0) res += dfs(p - 1, st / i, lmt && i == maxx, i == 0 && lead);
            } else if(i && st % i == 0) 
                res += dfs(p - 1, st / i, lmt && i == maxx, i == 0 && lead);
        }
        if(!lmt && !lead) f[p][get(st)] = res;
        return res;
    } 
    
    void solve(ll x) {
        int tot = 0;
        while(x) {
            di[++tot] = x % 10;
            x /= 10;
        }
        for(int i = 0; i < pd.size(); i++) {
            cnt[i] = dfs(tot, pd[i], 1, 1);
            cnt[i];
        }
    }
    
    void init() {
        for(int i = 1; i <= 9; i++) {
            num[1][i].insert(i);
        }
        for(int i = 2; i <= 12; i++) {
            for(int j = 1; j <= 9; j++) {
                for(int k = 1; k <= j; k++) {
                    for(auto v : num[!(i % 2)][k]) {
                        num[i % 2][j].insert(v * j);
                    }
                }
            }
        }
        set<ll> tmp;
        for(int i = 1; i <= 9; i++) {
            for(auto v : num[0][i]) {
                tmp.insert(v);
            }
            for(auto v : num[1][i]) {
                tmp.insert(v);
            }
        }
        for(auto v : tmp) pd.push_back(v); 
    }
    
    struct node {
        ll res;
        int p1, p2;
        bool operator < (const node& a) const {
            return res < a.res;
        }
    };
    
    priority_queue<node> q;
    
    int main() {
        IOS;
        memset(f, -1, sizeof f);
        init();
        ll n;
        int k;
        cin >> n >> k;
        solve(n);
        vector<ll> ans;
        sort(cnt, cnt + pd.size(), greater<ll>());
        int len = min(k, (int)pd.size());
        for(int i = 0; i < len; i++) {
            q.push(node{cnt[i] * cnt[0], i, 0});
        }
        ll res = 0;
        for(int i = 0; i < k; i++) {
            auto mi = q.top();
            q.pop();
            res += mi.res;
            res %= M;
            int p1 = mi.p1;
            int p2 = mi.p2 + 1;
            q.push(node{cnt[p1] * cnt[p2], p1, p2});
        }
        cout << res << endl;
    }
    
  • 相关阅读:
    ES查询直方图聚合区间结果min越界问题
    yarn命令操作
    Hve on Spark left join的hashTable问题
    基于HUE可视化的大数据权限管理
    Android 制作圆角阴影的卡片
    Android 解决问题“Failed to resolve: com.android.support:design:26.1.0”
    Android 修改虚拟键栏背景颜色
    ArrayList的传值问题
    swift 网络请求中含有特殊字符的解决方案
    Android适配器
  • 原文地址:https://www.cnblogs.com/limil/p/13537989.html
Copyright © 2011-2022 走看看