CF908G New Year and Original Order

http://codeforces.com/problemset/problem/908/G

题解

考虑一个数的答案怎么算。
比如说32214。
我们求出大于等于1的数的个数,为5个,那么加上5*11111。

大于等于2的数有4个,加上4*1111。

大于等于3的有2个,加上3*111。

大于等于4的有1个吗,加上4*1。

最后发现等于12234,正好计算出了答案。

所以我们直接设计状态\(dp[i][j][k][0/1]\)表示前\(i\)位,大于等于数字\(k\)的有\(j\)个,是否卡边界。

代码

#include<bits/stdc++.h>
#define N 702
using namespace std;
typedef long long ll;
const int mod=1e9+7;
char s[N];
int n;
int dp[N][N][10][2];
inline ll rd(){
    ll x=0;char c=getchar();bool f=0;
    while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return f?-x:x;
}
inline void MOD(int &x){x=x>=mod?x-mod:x;}
inline void MOD(ll &x){x=x>=mod?x-mod:x;}
int main(){
    scanf("%s",s+1);
    n=strlen(s+1);
    for(int i=1;i<=n;++i)s[i]-='0';
    for(int i=0;i<10;++i)dp[0][0][i][1]=1;
    for(int i=0;i<n;++i)
      for(int j=0;j<=i;++j)
        for(int k=1;k<=9;++k)
          for(int p=0;p<2;++p)if(dp[i][j][k][p])
            for(int l=0;l<=9;++l){
                if(p&&l>s[i+1])continue;
                MOD(dp[i+1][j+(l>=k)][k][p&&(l==s[i+1])]+=dp[i][j][k][p]);
            }
    ll ans=0;
    for(int i=1;i<10;++i){
        ll nw=1;
        for(int j=1;j<=n;++j)
          MOD(ans+=nw*(dp[n][j][i][0]+dp[n][j][i][1])%mod),MOD(nw=nw*10%mod+1);
    }
    cout<<ans;
    return 0;
}

转载于:https://www.cnblogs.com/ZH-comld/p/11099931.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值