设S(x)表示十进制表示下x的每位数字之和,当S(A)>S(B)时,(A,B)表示一个和谐对。
给定N,求满足 的和谐对(A,B)的数量,答案对 取模。
题意:求1<=A<=B<=N,满足S(A)>S(B)的(A,B)个数 s是数码和。
题解:数位dp。定义dp[n][d][f0][f1],其中n表示从最高位开始,前n-1位都已经确定,正在处理第n位。
d表示前n-1位的数值中,A-B的差值,这里要注意A-B可能为负,因此当差值为0时,应该将d设置为1000.
f0表示前n-1位中,A是否与B相同(相同为1)
f1表示前n-1位中,B是否与N相同(相同为1)
令a[n]为N的第n位的值,i为当前遍历的A的第n位的值,j为当前遍历的B的第n位的值,可以得到:
max(i)= j(f0==1)或者 9(f0==0)
max(j)= a[n](f1==1)或者9(f1==0)
则dp[n][d][f0][f1]=dp[n-1][d+i-j][f0&(i==j)][f1&(j==a[n])]
1 #include<cstdio> 2 #include<cstdlib> 3 #include<algorithm> 4 #include<cstring> 5 #include<queue> 6 #define ll long long 7 using namespace std; 8 ll const mod=1e9+7; 9 ll dp[105][2020][2][2]; 10 int a[105]; 11 char s[105]; 12 ll dfs(int n,int d,int f0,int f1){ 13 if (!n) return d>1000; 14 if (dp[n][d][f0][f1]!=-1) return dp[n][d][f0][f1]; 15 int l1= f1 ? a[n]:9; 16 ll temp=0; 17 for (int j=0;j<=l1;j++) //B 18 for (int i=0;i<=(f0?j:9);i++) //A 19 temp=(temp+dfs(n-1,d+i-j,f0&(i==j),f1&(a[n]==j)))%mod; 20 return dp[n][d][f0][f1]=temp; 21 } 22 int main(){ 23 memset(dp,-1,sizeof(dp)); 24 scanf("%s",s); 25 int n=strlen(s); 26 for (int i=0;i<n;i++) 27 a[n-i]=s[i]-'0'; 28 printf("%lld\n",dfs(n,1000,1,1)); 29 return 0; 30 }