2019 Multi-University Training Contest 8 1003 Acesrc and Good Numbers ——数位DP求n使得1-n中d的数量=n

This way

题意:

f ( d , x ) f(d,x) f(d,x)表示1-x中d的出现次数。现在给你d,n,让你求最大的x<=n使得 f ( d , x ) = x f(d,x)=x f(d,x)=x

题解:

它可以用两个函数表示:y=x和一个波动函数的交点即是 f ( d , x ) = x f(d,x)=x f(d,x)=x的解。那么如果 f ( d , n ) = n f(d,n)=n f(d,n)=n,答案就是n,否则将n-max(1,abs(f(d,n)-n)/17),因为n-1比n最多小18位,然后我们每次至少减1位,如此往复即可得到正解,而n与f(d,n)是同一个数量级的,那么其实要做的次数并不多。
记忆化搜索需要优化,对于当前位置,所有小于等于当前位置值得情况,都有 ( p o s − 1 ) ∗ 1 0 p o s − 2 (pos-1)*10^{pos-2} (pos1)10pos2种情况,这个手模一下即可得到:
1-9有1种可能,1-99有210种可能,1-999有3100种可能。。。
那么对于当前位置是d的情况,分成两种:如果它不是上界,那么有 1 0 p o s − 1 10^{pos-1} 10pos1种可能,否则就是剩下的数种可能,比如d=1
那么2000的时候1在第4位有1000种可能,但是1005时,只有6种可能。

#include
using namespace std;
#define ll long long
ll p[20],nex[20],a[20];
int d;
ll dfs(int pos)
{
    if(pos<=0)
        return 0;
    ll ans=(ll)(a[pos])*(pos-1)*(pos-2>=0?p[pos-2]:0ll)+(d=0?x-y:y-x)/18,1ll);
            ret=x;
            for(int i=1;i<20;i++)
                a[i]=ret%10,nex[i]=nex[i-1]+a[i]*p[i-1],ret/=10;
            y=dfs(19);
        }
        printf("%lld\n",x);
    }
    return 0;
}

你可能感兴趣的:(想法,dfs,dp)