『8.21 模拟赛』Victory
Posted fang-hao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了『8.21 模拟赛』Victory相关的知识,希望对你有一定的参考价值。
题目描述
迟到大王rsw喜欢V这个字母,因为V代表着victory,当一个数字,从左向右数的时候,没有出现过先递减,再递增的情况,就被称作Victory数。
也就是说,这个数字可以是递增的,也可以是递减的,也可以是先递减再递增的,这个过程中可以出现相邻数字相等的情况,但是,就是不能出现过先递减再递增的情况。
问题是:给定n,问:1~n之间有多少个victory数。
解题思路
我们应该一眼就能看出这是一道数位dp题,一开始用3维dp写,状态不够写挂了。。。后来改用4维就A了。
我们用dp[ i ][ j ][ k ][ l ] 来表示当前选到了第i位,当前选择的数是j,(k=0)表示当前的状态是递增的,(k=1)表示当前的状态是递减的,(l=0)表示当前没有遇到上界,(l=1)表示当前遇到了上界。但是在转移的时候有很多的细节,所以我们要慢慢分析:
比如,上升和下降并不是严格的,所以我们一定要注意一下,比如还没有出现严格上升的时候的k一直等于1,也就是递减的,遇到了一次严格递增的我们就把k严格设置成0,这样我们就可以防止重复情况的计算。
我们dfs的时候一定要注意前导0对答案的影响:比如098是一个合法的三位数,但是我们很容易漏掉他,一开始在这挂了好久,我们从每一位开始枚举,注意枚举最高位的时候l的取值。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define LL long long
using namespace std;
const LL MOD=1000000007;
char n[150];
int len,a[150];
LL dp[102][11][2][2];
inline LL dfs(int wei,int num,bool ud,bool flag){
if(wei==1)return 1;
if(dp[wei][num][ud][flag])return dp[wei][num][ud][flag];
if(ud==0){
if(flag){
for(register int i=num;i<=a[wei-1];i++){
if(i==a[wei-1]){
dp[wei][num][ud][flag]+=dfs(wei-1,i,ud,1);
dp[wei][num][ud][flag]%=MOD;
}
else {
dp[wei][num][ud][flag]+=dfs(wei-1,i,ud,0);
dp[wei][num][ud][flag]%=MOD;
}
}
}
else {
for(register int i=num;i<=9;i++){
dp[wei][num][ud][flag]+=dfs(wei-1,i,ud,0);
dp[wei][num][ud][flag]%=MOD;
}
}
return dp[wei][num][ud][flag];
}
else {
if(flag){
for(register int i=0;i<=min(num,a[wei-1]);i++){
if(i==a[wei-1]){
dp[wei][num][ud][flag]+=dfs(wei-1,i,ud,1);
dp[wei][num][ud][flag]%=MOD;
}
else {
dp[wei][num][ud][flag]+=dfs(wei-1,i,ud,0);
dp[wei][num][ud][flag]%=MOD;
}
}
for(register int i=num+1;i<=a[wei-1];i++){
if(i==a[wei-1]){
dp[wei][num][ud][flag]+=dfs(wei-1,i,0,1);
dp[wei][num][ud][flag]%=MOD;
}
else {
dp[wei][num][ud][flag]+=dfs(wei-1,i,0,0);
dp[wei][num][ud][flag]%=MOD;
}
}
}
else {
for(register int i=0;i<=num;i++){
dp[wei][num][ud][flag]+=dfs(wei-1,i,1,0);
dp[wei][num][ud][flag]%=MOD;
}
for(register int i=num+1;i<=9;i++){
dp[wei][num][ud][flag]+=dfs(wei-1,i,0,0);
dp[wei][num][ud][flag]%=MOD;
}
}
return dp[wei][num][ud][flag];
}
}
int main(){
scanf("%s",n+1);
len=strlen(n+1);
for(register int i=1;i<=len;i++){
a[len+1-i]=(int)(n[i]-'0');
}
LL ans=0;
for(register int i=1;i<=a[len];i++){
if(i!=a[len])ans+=dfs(len,i,1,0);
else ans+=dfs(len,i,1,1);
ans%=MOD;
}
for(register int i=len-1;i>=1;i--){
memset(dp,0,sizeof(dp));
for(register int j=1;j<=9;j++){
ans+=dfs(i,j,1,0);
ans%=MOD;
}
}
cout<<ans<<endl;
}
以上是关于『8.21 模拟赛』Victory的主要内容,如果未能解决你的问题,请参考以下文章