2020牛客多校第六场 H Harmony Pairs(数位DP)

H Harmony Pairs(数位DP)

题目传送门

Harmony Pairs

思路

题意:求 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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值