题解 P1874 【快速求和】

· · 题解

考虑迭代加深的搜索方式。

我们从0开始枚举可能的答案,然后进行搜索。

有三个显然的剪枝,运用之后可以提升程序的效率(仍然很慢),但编码(和思维)难度并没有提升。

对于剪枝2,我们维护一个后缀和数组sum;

对于剪枝3,我们实现一个(套)函数:它支持在一个数字字符串里找到一个子段并将其转换成数字。

#include<bits/stdc++.h>
using namespace std;

char line[41];
int sum[42];
int n,l;

inline int num(const int &l,const int &r){
    int res=0;
    for(int i=l+1;i<=r;++i) res=res*10+line[i]-'0';
    return res;
}

inline bool enough(const int &last,const int &val){
    int i;
    for(i=last+1;line[i]-'0'==0;++i);
    if(l-i+1>=9) return true;
    return num(i-1,l)>=n-val;
}

int ans;

bool dfs(int last,int cnt,int val){
    if(cnt>ans) return false;//1
    if(last==l) return val==n; 
    if(val+sum[last+1]>n) return false;//2
    if(!enough(last,val)) return false;//3
    for(int now=last+1;val+num(last,now)<=n;++now)
        if(dfs(now,cnt+(now!=l),val+num(last,now))) return true;
    return false;
}

void read(){
    scanf("%s %d",line+1,&n);
    l=strlen(line+1);
    for(int i=l;i;--i) sum[i]=sum[i+1]+line[i]-'0';
}

void solve(){
    for(ans=0;!dfs(0,0,0) and ans<l;++ans);
    cout<<(ans==l?-1:ans);
}

int main(){
    read();
    solve();
    return 0;
}