gym101964A Numbers

        题解:搜索剪枝,特殊情况记忆化搜索,这题写了好久啊,例子:99999999999999999,这个跑出来答案有800000000。8亿,单纯的搜索肯定会t的,可以大概验证一下如果两个加数的长度不一样那么,方案数是很少的这种情况考虑搜索剪枝,而如果长度是一样的考虑记忆化搜索。那么如何剪枝呢?我们枚举一个加数(记为a)的位数最高位,那么同样知道这个加数的最低位。同理我会知道另外一个加数(记为b)的最低位(显然),那么同理b的最高位有两种情况,就是n-a这个数本身的最高位,或者是n-a这个数最高位减一(减一可能减为负数,那么这里又要分类讨论)。 

        这里多给几个样例:

​
#include 

using namespace std;
typedef long long LL;
const int maxn = 1e5+7;
LL n,a[21],b[21],mul[21];

int get_num(LL x){
    int num = 0;
    do{
        ++num;
        x /= 10;
    }while(x);
    return num;
}
bool check(){
    int ed = 0;
    for(int i = 18; i >= 1; i--){
        if(b[i]){
            ed = i;
            break;
        }
    }
    for(int i = 1,j = ed; i <= ed/2; ++i,--j){
        if(b[i]/mul[i] != b[j]/mul[j]) return 0;
    }
    return 1;
}
inline bool judge(int l, int r){
    return (b[l]/mul[l] == b[r]/mul[r]);
}

#define mp make_pair
map,LL> dp;
LL dfs(int dep, LL x, int l, int r, int bh, int len){
    if(l > r){
        if(!check()) return 0;
        LL tx = 0, ty = 0;
        for(int i = 0; i <=18; i++)
            tx += a[i], ty += b[i];
        if(tx + ty != n) return 0;
        if(tx > 0 && ty > 0){
            if(bh == len) return 1;
            if(tx > ty) return 2;
            else if(tx == ty) return 1;
        }
        return 0;
    }
    if(bh == len){
        if(dp.count(mp(x,l))) return dp[mp(x,l)];
    }
    LL ans = 0;
    for(int i = dep? 0 : 1; i <= 9; i++){
        b[l] = b[r] = 0;
        a[l] = mul[l]*i;
        a[r] = mul[r]*i;

        LL y = x-a[l]-a[r];
        if(l == r) y += a[l];
        if(y < 0) continue;

        b[l] = y/mul[l]%10*mul[l];
        y -= b[l];
        int nbh = bh;
        if(l < r){
            b[r] = y/mul[r]%10*mul[r];
            y -= b[r];
        }
        if(y >= 0 && y < mul[r]){
            if(!bh && b[r] > 0) nbh = r;
            if(!nbh) ans += dfs(dep+1,y,l+1,r-1,nbh, len);
            else if(judge(nbh-r+1,r)) ans += dfs(dep+1,y,l+1,r-1,nbh, len);
        }

        if(l == r) continue;
        if(b[r] >= mul[r]){
            b[r] -= mul[r];
            y += mul[r];
            nbh = bh;
            if(y >= 0 && y < mul[r]*2){
                if(!bh && b[r] > 0) nbh = r;
                if(!nbh) ans += dfs(dep+1,y,l+1,r-1,nbh, len);
                else if(judge(nbh-r+1,r)) ans += dfs(dep+1,y,l+1,r-1,nbh, len);
            }
        }
        else{
            y += b[r];
            b[r] = 9*mul[r];
            y -= b[r];
            if(y >= 0 && y < mul[r]*2){
                if(!bh && b[r] > 0) nbh = r;
                if(!nbh) ans += dfs(dep+1,y,l+1,r-1,nbh, len);
                else if(judge(nbh-r+1,r)) ans += dfs(dep+1,y,l+1,r-1,nbh, len);
            }
        }

    }
    if(bh == len) dp[mp(x,l)] = ans;
    return ans;
}

int main() {
    cin>>n;
    mul[0] = mul[1] = 1;
    for(int i = 2; i <= 19; i++) mul[i] = mul[i-1]*10;
    int num = get_num(n);
    LL ans = 0;
    ans += dfs(0,n,1,num,0, num);
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    dp.clear();
    ans += dfs(0,n,1,num-1,0, num-1);
    cout<

 

你可能感兴趣的:(DP,思维,搜索)