2020牛客暑期多校训练营(第六场)H Harmony Pairs —— 记忆化搜索,有丶东西
程序员文章站
2022-06-27 17:22:52
This way题意:定义S(x)=十进制下x所有位的和。问你有多少对A,B使得S(A)>S(B)&&A<=B题解:我一开始题目看错了,没注意到A和B的大小关系,所以一开始的数位DP就写错了,看对题目之后我往生成树那方面去想,想找子树大小什么的关系,但是最后找不出来…赛后看了别人的代码,真的太强了,或许这才是记忆化搜索吧…dp[i][j][k][l]表示到了第i个位置,当前数的和为j,k表示较大数是否到达上界,l表示较小数是否到达上界。后面这两维真的精髓,这样就可以...
题意:
定义S(x)=十进制下x所有位的和。问你有多少对A,B使得S(A)>S(B)&&A<=B
题解:
我一开始题目看错了,没注意到A和B的大小关系,所以一开始的数位DP就写错了,看对题目之后我往生成树那方面去想,想找子树大小什么的关系,但是最后找不出来…赛后看了别人的代码,真的太强了,或许这才是记忆化搜索吧…
dp[i][j][k][l]表示到了第i个位置,当前数的和为j,k表示较大数是否到达上界,l表示较小数是否到达上界。
后面这两维真的精髓,这样就可以将较大的数和较小的数区分开来。然后每次枚举的时候,i表示较大数,j表示较小数,sum+j-i表示他们的差加了多少。最后如果sum>N的话,就表示较小数的位上的和大于较大数。
tql/QAQ.jpg
#include<bits/stdc++.h>
using namespace std;
const int N=905,M=105;
#define ll long long
const ll mod=1e9+7;
ll dp[M][N*2][2][2];
char s[N];
int n;
ll dfs(int pos,int sum,int m1,int m2){
if(pos>n)
return sum>N;
if(~dp[pos][sum][m1][m2])
return dp[pos][sum][m1][m2];
ll ans=0;
int top=m1?s[pos]-'0':9;
for(int i=0;i<=top;i++){
int t2=m2?i:9;
for(int j=0;j<=t2;j++)
ans=(ans+dfs(pos+1,sum+j-i,m1&&i==top,m2&&j==t2))%mod;
}
dp[pos][sum][m1][m2]=ans;
return ans;
}
int main()
{
memset(dp,-1,sizeof(dp));
scanf("%s",s+1);
n=strlen(s+1);
printf("%lld\n",dfs(1,N,1,1));
return 0;
}
本文地址:https://blog.csdn.net/tianyizhicheng/article/details/107617565
上一篇: 我们刚刚添了一个孙孙