E - Digit Products 实在是瞎搞

8 篇文章 0 订阅
本文介绍了一种解决整数乘积组合问题的方法,通过分段处理(无0和有0部分)、动态规划和容斥原理,计算给定数字范围内可能的最优乘积组合。使用了unordered_map和递推思想,适用于整数部分的9进制数乘积计算。
摘要由CSDN通过智能技术生成

首先我是想把题目分成好几部分来做 首先是第一部分 列如88897 我们找到它的最高位 然后先把10000以下的算出来 如何去算呢 分成两部分 一部分是 没有0的 一部分是有0的 有0这一部分用dp + map就可以了因为 最多组成的乘积有 9^9 / 9! 为1000多一点 所以开map是完全没问题的 没有0的部分用容斥的思想 就是全部数减掉 每位都>=1 的情况
因为我们这个是只能在整数部分 就是后面每位都可以取到9的情况 我们不妨从前往后 把每一位的小一位取出来 去求 数量 最后统计一下即可

#include<iostream>
#include<unordered_map>

using namespace std;

typedef long long ll;

const int N = 1e5 + 10;

unordered_map<ll,ll>mp[25];

ll b[N];

ll qpow(ll a,ll b){
    ll s = 1;
    while(b){
        if(b & 1) s = s * a;
        a = a * a;
        b >>= 1;
    }
    return s;
}

int main(){
    ll n,m;
    cin >> n >> m;

    ll s = n,dig = 0;
    while(s){
        s /= 10;
        dig++;
    }

    ll sum = 0,cnt = 0;
    for(ll i = 1; i <= 9; i++){
        if(!mp[1][i] && i <= m){
            b[++cnt] = i;
            mp[1][i] = 1;
            sum += 1;
        }
    }

    for(ll i = 2; i <= dig - 1; i++){
        ll sb = cnt;
        for(ll j = 1; j <= sb; j++){
            for(ll k = 1; k <= 9; k++){
                if(!mp[i - 1][b[j] * k] && !mp[i][b[j] * k]){
                    if(b[j] * k <= m){
                        sum += mp[i - 1][b[j]];
                        b[++cnt] = b[j] * k;
                        mp[i][b[j] * k] += mp[i - 1][b[j]];
                    }
                }else{
                    if(b[j] * k <= m){
                        mp[i][b[j] * k] += mp[i - 1][b[j]];
                        sum += mp[i - 1][b[j]];
                    }

                }
            }
            //cout << i << " " << b[j] << " " << mp[i][b[j]] <<endl;
        }
    }

    for(ll i = dig; i >= 2; i--){
        sum += 9 * qpow(10,i - 2) - qpow(9,i - 1);
        //cout << i - 1 << " " << 9 * qpow(10,i - 2) - qpow(9,i - 1)  << "Asd" <<endl;
    }

    /*cout <<sum << endl;
    for(int i = 1; i <= cnt; i++){
        cout <<b[i] << ' ' << mp[1][b[i]] << endl;
    }*/
    mp[0][1] = 1;
    s = 1;
    for(ll i = dig; i >= 1; i--){
        //cout << sum << endl;
        if(s == 0){
            sum += n % qpow(10,i);
            break;
            return 0;
        }
        for(ll j = ((n / qpow(10,i - 1)) % 10) - 1; j >= 1; j--){
            for(ll k = 1; k <= cnt; k++){
                if(b[k] * s * j <= m){
                        //cout << i << " " << j << " " << b[k] <<" " << mp[i - 1][b[k]] << "ASDA" << endl;
                    sum += mp[i - 1][b[k]];
                }
            }
        }
        if(i != dig && ((n / qpow(10,i - 1)) % 10) >= 1) sum += (((n / qpow(10,i - 1)) % 10)) * qpow(10,i - 1) - (((n / qpow(10,i - 1)) % 10) - 1) * qpow(9,i - 1);
        if(i == dig && ((n / qpow(10,i - 1)) % 10) >= 2) sum += (((n / qpow(10,i - 1)) % 10) - 1) * qpow(10,i - 1) - (((n / qpow(10,i - 1)) % 10) - 1) * qpow(9,i - 1);
        //cout <<sum << "TTT" <<endl;
        s *= ((n / qpow(10,i - 1)) % 10);
       // cout <<s <<"GG"<< endl;
     }

    if(s <= m) sum++;
    cout << sum << endl;

    /*int ss = 0;
    for(int i = 1; i <= n; i++){
        int s = i,g = 1;
        while(s){
            g *= s % 10;
            s /= 10;
        }
        if(g <= m) ss++;

    }
    cout << ss << "Asd" << endl;*/





    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值