Codeforces908 G. New Year and Original Order(数位dp)

题意:

在这里插入图片描述

解法:
数位dp.

显然数字排序后一定是非递减的.
对于22345,可以拆分为:
11111
11111
  111
   11
    1
发现第i行中1的个数就是>=i的数字个数.
因此数字i的贡献就是[1,X]>=i的数字个数.[1,9]枚举j,令d[i][k][l]表示高i位,>=j的数有k个,最高位限制为l的方案数.
枚举下一位的数字选择,dp一下即可.
对于固定的j,ans+=p[k]*(d[n][k][0]+d[n][k][1]),其中p[k]为k个连续1的值.
code:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=700+5;
const int mod=1e9+7;
int d[maxm][maxm][2];
int p[maxm];
char s[maxm];
int n;
signed main(){
    ios::sync_with_stdio(0);
    for(int i=1;i<maxm;i++)p[i]=(p[i-1]*10+1)%mod;
    cin>>(s+1);
    n=strlen(s+1);
    for(int i=1;i<=n;i++)s[i]-='0';
    int ans=0;
    for(int j=1;j<=9;j++){
        memset(d,0,sizeof d);
        for(int x=0;x<=s[1];x++){
            d[1][x>=j][x==s[1]]++;
        }
        for(int i=1;i<=n-1;i++){
            for(int k=0;k<=i;k++){
                for(int l=0;l<2;l++){//枚举当前状态
                    if(!d[i][k][l])continue;
                    int ma=(l?s[i+1]:9);//下一个数的枚举范围
                    for(int x=0;x<=ma;x++){//枚举下一个数
                        d[i+1][k+(x>=j)][l&&(x==ma)]+=d[i][k][l];
                        d[i+1][k+(x>=j)][l&&(x==ma)]%=mod;
                    }
                }
            }
        }
        for(int k=0;k<=n;k++){
            ans+=p[k]*(d[n][k][0]+d[n][k][1])%mod;
            ans%=mod;
        }
    }
    cout<<ans<<endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值