题目大意:

定义\(R(x) = 每个数在各数位排序后得到的数\)
例如:\(R(321597) = 123579\)
给定一个\(n<=10^{700}\),求\(\sum _{i=1}^n R(i)\)。答案模上\(10^9+7\)。

思路与解法:

难度比较大的一题。显然是要数位\(DP\)的。
最直白的想法就是:求出\(g[i][j]\)表示数字在\(R(x)\)的第\(j\)位出现的次数。
有了这个我们就可以计算答案了。 但是这个玩意不好\(DP\)处理。
考虑数字\(num\)在\(f(x)\)的第\(j\)位出现的条件:\(R(x)\)中大于等于\(num\)的数字有\(j\)个。
这个东西就可以\(DP\)了:
\(f[i][j][k][0/1]\)表示当前确定了\(i\)位数字,
数位中大于等于\(k\)的数位有\(j\)个,数位限制状态为\(0/1\)的数的个数。
转移比较简单,枚举下一位放什么即可。
然后初值不好处理,所以手玩\(i=1\)的,把\(i=1\)当初值就行了。
处理出了\(f[n][j][num][1]\)后,就比较好算答案了。
.
记录后缀和\(ans[num][j] = \sum_{i=j}^n f[n][i][num][1]\)。
那么\(g[i][j] = ans[num][j] - ans[num+1][j]\),就把\(g[i][j]\)求出来了。
然后用\(g[i][j]\)直接计算答案即可。

实现代码:

注:屏幕较窄的电脑上看 代码可能格式不太好,最好拷贝到编辑器后再看。

#include<bits/stdc++.h>
#define RG register
#define IL inline
#define ll long long
#define _ 705
#define mod 1000000007
using namespace std;

ll Ans,ten; int n , num[ _ ];
ll f[ _ ][ _ ][ 10 ][ 2 ],ans[ _ ][ _ ]; char ch[ _ ];

IL void Add(RG ll &x,RG ll y){ x += y; if(x>=mod)x-=mod; }

int main(){
    scanf("%s",ch); n = strlen( ch );
    for(RG int i = 1; i <= n;i ++)
        num[i] = ch[ n-i ] - '0';
    for(RG int t = 0; t <= 9; t ++){
        if(t > num[1])
            f[1][0][t][0] = t , f[1][0][t][1] = num[1]+1 , f[1][1][t][0] = 10-t , f[1][1][t][1] = 0;
        else
            f[1][0][t][0] = t , f[1][0][t][1] = t , f[1][1][t][0] = 10-t , f[1][1][t][1] = num[1]-t+1;
    }
    for(RG int i = 2; i <= n; i ++){
        for(RG int j = 0; j <= i; j ++)
            for(RG int k = 0; k <= 9; k ++){
                for(RG int t = 0; t <= 9; t ++){
                    if(t >= k){
                        Add( f[i][j][k][0] , f[i-1][j-1][k][0] );
                        if( t < num[i] )
                            Add( f[i][j][k][1] , f[i-1][j-1][k][0] );
                        else if( t == num[i] )
                            Add( f[i][j][k][1] , f[i-1][j-1][k][1] );
                    }
                    else if(t < k){
                        Add( f[i][j][k][0] , f[i-1][j][k][0] );
                        if( t < num[i] )
                            Add( f[i][j][k][1] , f[i-1][j][k][0] );
                        else if( t == num[i] )
                            Add( f[i][j][k][1] , f[i-1][j][k][1] );
                    }
                }
            }
        }
    for(RG int nm = 0; nm <= 9; nm ++)
        for (int i = n ; i >= 1 ; i --)
            (f[n][i][nm][1] += f[n][i+1][nm][1]) %= mod , ans[nm][i]=f[n][i][nm][1];
    Ans = 0; ten = 1;
    for(RG int i = 1; i <= n; ten*=10,ten %= mod,i ++)
        for(RG int nm = 1; nm <= 9; nm ++)
            Add( Ans , ( ((ans[nm][i] - ans[nm+1][i]) % mod + mod) % mod * ten % mod * nm % mod) );
    cout << Ans;  return 0;
}

CF908G Original Order的更多相关文章

  1. 【CF908G】New Year and Original Order(动态规划)

    [CF908G]New Year and Original Order(动态规划) 题面 洛谷 CF 题解 设\(f[i][j][k][0/1]\)表示当前填到了第\(i\)位,有\(j\)个大于等于 ...

  2. 【CF908G】New Year and Original Order 数位DP

    [CF908G]New Year and Original Order 题意:令S(i)表示将i中所有数位上的数拿出来,从小到大排序后组成一个新的数的值.如S(50394)=3459.求$\sum\l ...

  3. 【CF908G】New Year and Original Order

    [CF908G]New Year and Original Order 题面 洛谷 题解 设\(f[i][j][k][l]\)表示当前在第\(i\)位有\(j\)位大于等于\(k\),当前有没有卡上界 ...

  4. Good Bye 2017 G. New Year and Original Order

    G. New Year and Original Order time limit per test 2 seconds memory limit per test 256 megabytes inp ...

  5. CF908G New Year and Original Order 数位DP

    传送门 看到数据范围到\(10^{700}\)毫无疑问数位DP.那么我们最重要的问题是如何有效地维护所有数位排序之后的数的值. 对于某一个数\(x\),设\(f_{x,i} (i \in [1,9]) ...

  6. CF908G New Year and Original Order

    题面 题意翻译 给定$n<=10^{700}$,问$1$到$n$中每个数在各数位排序后得到的数的和.答案$mod\;10^9+7$. 题解 考虑设$f[i][j][k][0/1]$表示前$i$位 ...

  7. CF908G New Year and Original Order(DP,数位 DP)

    又一次降智…… (数位 DP 原来可以写这么短,学到了) 问题可以转化为求数位中 $\ge k$ 的有恰好 $j$ 位的数的个数.设为 $c_{j,k}$. 那么答案就是:(考虑把 $k$ 的贡献拆开 ...

  8. 908G New Year and Original Order

    传送门 分析 代码 #include<iostream> #include<cstdio> #include<cstring> #include<string ...

  9. Codeforces908G. New Year and Original Order

    给n<=10^700,问1到n中每个数在各数位排序后得到的数的和.答案膜1e9+7. 一看就是数位DP啦..然而并没有什么思路.. 可以尝试统计n(i,j)表示数j在第i位的出现次数,知道了这个 ...

随机推荐

  1. Java中excel与对象的互相转换的通用工具类编写与使用(基于apache-poi-ooxml)

    通用excel与对象相互转换的工具类 前言:最近开发需要一个Excel批量导入或者导出的功能,之前用过poi-ooxml开发过一个导入的工具类,正好蹭着这次机会,把工具类的功能进行完善. 使用说明: ...

  2. NoSQLBooster for MongoDB的基本使用

    连接 File -> Quik Connect ( Ctrl + Shift + N ) 或 Connect -> From URI 填入 mongodb://username:passw ...

  3. http权威指南笔记

    请求报文 响应报文GET /test/hi.txt HTTP/1.0 起始行 HTTP/1.0 200 OKAccept: text/* 首部 Content-type: text/plainAcce ...

  4. FIO性能测试

    FIO参数中,ioengine使用libaio,并发jobs数固定为1,通过iodepth来控制压力.分别测试随机读.随机写,作为读写的性能基准.不测试顺序读写,不测试混合读写. 1.测试IOPS峰值 ...

  5. Netbeans文件被误删怎么办?

    辛辛苦苦写的代码突然不见了,上午还是有的,哪去了?怎么办? 破解办法: 1,良好的版本管理工具(git||svn)使用习惯,代码每天上传更新,技术文件有丢失,也就一天的. 2,Netbeans提供的备 ...

  6. 优化Linux内核参数提高服务器负载能力

    首先,编辑一下/etc/sysctl.conf 文件,调整一下以下参数,如果没有经过优化的Linux内核可能没有这些参数,那么把需要补充的复制添加进去即可,其他设置默认即可,不需要理解. 记得修改完成 ...

  7. MysqL 磁盘写入策略之innodb_flush_log_at_trx_commit

    本文从参数含义,性能,安全角度阐述两个参数为不同的值时对db 性能,数据的影响,引擎是Innodb的前提下. 取值:0/1/2 innodb_flush_log_at_trx_commit=0,表示每 ...

  8. POJ - 2253 Frogger 单源最短路

    题意:给定n个点的坐标,问从第一个点到第二个点的最小跳跃范围.d(i)表示从第一个点到达第i个点的最小跳跃范围. AC代码 #include <cstdio> #include <c ...

  9. Linux下安装MySQL数据库(压缩包方式安装)

    1.这里我将Mysql安装在/usr/local/mysql目录里面,也可以安装在其他地方; mkdir /usr/local/mysql 2.下载MySQL压缩包 wget http://dev.M ...

  10. python语言中的AOP利器:装饰器

    一.前言 面向切面编程(AOP)是一种编程思想,与OOP并不矛盾,只是它们的关注点相同.面向对象的目的在于抽象和管理,而面向切面的目的在于解耦和复用. 举两个大家都接触过的AOP的例子: 1)java ...