码迷,mamicode.com
首页 > 其他好文 > 详细

CF908G Original Order

时间:2018-02-04 00:30:21      阅读:139      评论:0      收藏:0      [点我收藏+]

标签:for   can   次数   编辑   inline   include   sum   排序   解法   

题目大意:

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

思路与解法:

难度比较大的一题。显然是要数位\(DP\)的。
最直白的想法就是:求出\(g[i][j]\)表示数字在\(f(x)\)的第\(j\)位出现的次数。
有了这个我们就可以计算答案了。 但是这个玩意不好\(DP\)处理。
考虑数字\(num\)\(f(x)\)的第\(j\)位出现的条件:\(f(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

标签:for   can   次数   编辑   inline   include   sum   排序   解法   

原文地址:https://www.cnblogs.com/GuessYCB/p/8411152.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!