H Harmony Pairs(数位DP)
题目传送门
思路
题意:求 1 < = A < = B < = N 1<=A<=B<=N 1<=A<=B<=N,满足 S ( A ) > S ( B ) S(A)>S(B) S(A)>S(B)的 ( A , B ) (A,B) (A,B)个数 s s s是数码和
很明显的数位DP,但是不会…,所以补一下
最大为 1 0 100 10^{100} 10100 ,所以最大的数的每位都是9,最小0,所以每个位的差值不会超过1000,所以用1000为底防止负数
DP[109][2009][2][2]; //分别对应 位数、两数的各位差、第一位的最高位的限制、第二位最高位的限制
说明麻烦,直接看DFS函数吧,
int DFS(int pos, int ans, bool signa, bool signb){
if(pos<0) return ans>init;
if(DP[pos][ans][signa][signb]!=-1) return DP[pos][ans][signa][signb];
ll res=0;
ll lima= signa ? s[pos]-'0':9; //对数是否有限制
for(int i=0; i<=lima; i++){
for(int j=0; j<=(signb ? i:9); j++){ //题意第二个数i大于第一个数j(即为:i>j
res=(res+DFS(pos-1, ans+j-i, signa&&i==lima, signb&&i==j))%mod;
}
}
return DP[pos][ans][signa][signb]=res;
}
完整代码
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
// #define TDS_ACM_LOCAL
typedef long long ll;
const int mod=1e9 + 7;
const int init=1000; //两数之差的初始化(防止负数出现,+-1000)
int len;
string s;
ll DP[109][2009][2][2]; //分别对应 位数、两数的各位差、第一位的最高位的限制、第二位最高位的限制
int DFS(int pos, int ans, bool signa, bool signb){
if(pos<0) return ans>init;
if(DP[pos][ans][signa][signb]!=-1) return DP[pos][ans][signa][signb];
ll res=0;
ll lima= signa ? s[pos]-'0':9; //对数是否有限制
for(int i=0; i<=lima; i++){
for(int j=0; j<=(signb ? i:9); j++){ //题意第二个数i大于第一个数j(即为:i>j
res=(res+DFS(pos-1, ans+j-i, signa&&i==lima, signb&&i==j))%mod;
}
}
return DP[pos][ans][signa][signb]=res;
}
void solve(){
memset(DP, -1, sizeof(DP)); //初始化DP
cin>>s;
len=s.length();
for(int i=0; i<len/2; i++) swap(s[i], s[len-1-i]); //交换N的位次
cout<<DFS(len-1, init, 1, 1)<<endl;
return ;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
#ifdef TDS_ACM_LOCAL
freopen("D:\\VS code\\.vscode\\testall\\in.txt", "r", stdin);
freopen("D:\\VS code\\.vscode\\testall\\out.txt", "w", stdout);
#endif
solve();
return 0;
}