题解:P16140 圆圈函数(circle)
furina_hhz · · 题解
思路
注意到是统计合法数字个数的题目,考虑数位 DP。
先对原式做一个简单的变形。设
化简得:
所以问题便等价于合法的
开始设计数位 DP,因为存在进位,所以由低到高枚举数位。设
但是我们发现,
于是我们可以设计一个新的 DP 状态。
接下来就是数位 DP 板子了(链接是一道经典模板题,不会的可以去学习)。
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,m,sumbit,fn,ans,dp[20][80][2][2];
int cmp(int x){
if(!x || x == 4 || x == 6 || x == 9) return 1;
else if(x == 8) return 2;
else if(x < 10) return 0;
return cmp(x / 10) + cmp(x % 10);
}
int dfs(int bit,int mx,int r,int rm,int sum,bool b,bool c){
/*
最后的结果要满足:
1. a <= floor(n/10)
2. f(n+a) - f(a) = f(n)
*/
if(bit > mx) return (mx != sumbit || !b) && sum + (r + c ? cmp(r + c) : 0) == fn;
if(~dp[bit][40+sum][b][c]) return dp[bit][40+sum][b][c];
dp[bit][40+sum][b][c] = 0;
for(int i = bit == mx;i <= 9;i++){
int now = r % 10 + i + c;
dp[bit][40+sum][b][c] += dfs(bit + 1,mx,r / 10,rm / 10,sum + cmp(now % 10) - cmp(i),i + b > rm % 10,now > 9);
}
return dp[bit][40+sum][b][c];
}
signed main(){
scanf("%lld",&n);
sumbit = log10(n),m = n / 10 - 1,fn = cmp(n);
ans = min(10ll,n + 1);
// 枚举数字位数,消除前导零影响
for(int i = 1;i <= sumbit;i++){
memset(dp,-1,sizeof(dp));
ans += 10 * dfs(1,i,n,m,0,0,0);
}
if(sumbit && cmp(n + m + 1) == cmp(n) + cmp(m+1)) ans += n % 10 + 1;
cout << ans;
}