CCPC杭州站 HDU5936 Difference 搜索 剪枝

http://acm.hdu.edu.cn/showproblem.php?pid=5936



给出f(y,K)=z in every digits of yzK(f(233,2)=22+32+32=22)



问对于给定x和k,有几个y能让式子

x=f(y,K)y成立。

y是正整数

0x109 0≤x≤109
1K9

这样如果要让式子成立,那f(y, k)就要大于y,对于一个固定的y,肯定k越大,这个式子越容易成立,所以假设k都取9,我们尝试寻找最大的y是多少

如果y有9位,比如999999999,f(y,9) = 9^9 * 9 = 9^10 > y。继续枚举y有10位,9999999999,f(y,9) = 9^9 * 10 = 9^10 + 9^9 < y,所以y不可能多于10位。

那这样暴力枚举y效率还是不够,观察式子发现,f(y,k)的值和y具体是多少没关系,只与y的组成有关系(每个数字有几个)有关系,暴力搜索发现,y的组成只有几百万种。
这样我们通过搜索枚举y的组成,算出f(y, k),减去已知的x得到一个y值,再判断一下这个y值的组成与我们枚举的组成是否相同,如果相同,那这就是一个合法的y。


//
//  main.cpp
//  5936 Difference 搜索 (搜索 剪枝)
//
//  Created by czf on 2016/11/21.
//  Copyright © 2016年 czf. All rights reserved.
//

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;

LL fact[10][10], a[10], res, k, x; //a[]代表y的组成,a[i] = j表示i有j个。


void init() { //预处理次方
    for (int i = 0; i < 10; i ++) fact[i][0] = 1;
    for (int i = 0; i < 10; i ++) {
        for (int j = 1; j < 10; j ++) {
            fact[i][j] = fact[i][j-1] * i;
        }
    }
}

void dfs(int has, int pos) { //has表示接下来组成还能使用多少个数字,pos表示目前在枚举pos这个数字要用几次
    if (has == 0 || pos > 9) { //接下来没有数字可以用了,或者9个数字已经枚举完了
        LL sum = 0; //f(y, k)
        for (int i = 1; i < 10; i ++) {
            sum += fact[i][k] * a[i];
        }
        LL y = sum - x;
        if (y <= 0) return;
        LL b[10] = {0}; //算出来y值的组成
        while (y) {
            b[y%10] ++;
            y /= 10;
        }
        for (int i = 0; i < 10; i ++) { //判断枚举y的组成和算出来y的组成是否相同
            if (a[i] != b[i]) return;
        }
        res ++;
        return;
    }
    for (int i = 0; i <= has; i ++) { //枚举pos这个数字有几个
        a[pos] = i;
        dfs(has - i, pos + 1);
    }
}

int main() {
    init();
    int T, kase = 0; scanf("%d",&T);
    while (T--) {
        res = 0;
        memset(a, 0, sizeof(a));
        scanf("%lld%lld",&x,&k);
        dfs(10, 0);
        printf("Case #%d: %lld\n",++kase, res);
    }
    return 0;
}





等式

这个 问 d's等式
x = f ( y , K ) y,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值