傳送門
文章目錄
題意:
定義S(k)S(k)S(k)為將kkk的每一位拿出來從小到大排序后構成的數,比如S(3421)=1234S(3421)=1234S(3421)=1234,求S(k)1≤k≤nS(k)_{1\le k\le n }S(k)1≤k≤n?。
1≤n≤107001\le n\le 10^{700}1≤n≤10700
思路:
nnn很大,考慮數位dpdpdp。
由于直接處理不好弄,所以需要發現一些規律。
考慮一個數排好之后形式大概是這樣的:334593345933459,其中數一定是遞增的,我們發現它可以拆成如下形式:
111111111111111 111111111111111111111111111111111111111111111111111111111
假設從上到下某一行是第iii行,那么可以發現這一行111的個數就是≥i\ge i≥i的個數,這就啟發我們將每個數都分開考慮,設有lenlenlen個數≥x\ge x≥x,那么這個數的貢獻就是∑i=0len?110i\sum_{i=0}^{len-1}10^i∑i=0len?1?10i,考慮用dpdpdp求。
設f[i][j][k][flag]f[i][j][k][flag]f[i][j][k][flag]表示前iii位有jjj個大于≥k\ge k≥k個的數,以及是否壓上界,轉移的話按照數位dpdpdp的思想來轉移就好了:f[i][j+(x>=k)][k][flag∣(x<limit)]+=f[i?1][j][k][flag]f[i][j+(x>=k)][k][flag|(x<limit)]+=f[i-1][j][k][flag]f[i][j+(x>=k)][k][flag∣(x<limit)]+=f[i?1][j][k][flag]
可以發現kkk這一維是多余的,我們完全可以枚舉他,所以可以去掉這一維。
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#include<random>
#include<cassert>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid ((tr[u].l+tr[u].r)>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std
;
typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<int,int> PII
;const int N
=1000010,mod
=1e9+7,INF
=0x3f3f3f3f;
const double eps
=1e-6;int n
;
char s
[1010];
int f
[710][710][11][2];
void add(int &x
,int y
) {x
+=y
; if(x
>=mod
) x
-=mod
;
}int main()
{
cin
>>(s
+1);n
=strlen(s
+1);for(int i
=0;i
<=9;i
++) f
[0][0][i
][0]=1;for(int i
=1;i
<=n
;i
++) {for(int j
=0;j
<=i
;j
++) {for(int k
=0;k
<=9;k
++) {for(int flag
=0;flag
<=1;flag
++) {int limit
=flag
? 9:s
[i
]-'0';for(int x
=0;x
<=limit
;x
++) {add(f
[i
][j
+(x
>=k
)][k
][flag
|(x
<limit
)],f
[i
-1][j
][k
][flag
]);}}}}}int ans
=0;for(int i
=1;i
<=9;i
++)for(LL j
=1,fun
=1;j
<=n
;j
++) {add(ans
,1ll*fun
*(f
[n
][j
][i
][0]+f
[n
][j
][i
][1])%mod
);fun
=(1ll*fun
*10+1)%mod
;}cout
<<ans
<<endl
;return 0;
}
總結
以上是生活随笔為你收集整理的Good Bye 2017 G. New Year and Original Order 数位dp + 按数贡献的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。