Gym - 102040B Counting Inversion (数位dp)

题意:求[a,b]区间内的数字中正序对的个数。

具体思路参考:

https://blog.csdn.net/weixin_43135318/article/details/88061396

https://www.cnblogs.com/asdfsag/p/11278519.html

在此基础上维护一下每个状态中大于每个数字的数字出现的次数即可。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const ll N=20;
 5 ll bit[N],nbit,f[N][2][2],g[N][2][2][N],G[N][2][2],vis[N][2][2],ka,a,b,ka2;
 6 void dfs(ll u,ll ze,ll lim) {
 7     if(vis[u][ze][lim]==ka)return;
 8     vis[u][ze][lim]=ka;
 9     G[u][ze][lim]=0;
10     for(ll i=0; i<=9; ++i)g[u][ze][lim][i]=0;
11     if(u==0) {f[u][ze][lim]=1; return;}
12     f[u][ze][lim]=0;
13     for(ll i=0; i<=(lim?bit[u]:9); ++i) {
14         ll v=u-1,ze2=ze&&i==0,lim2=lim&&i==bit[u];
15         dfs(v,ze2,lim2);
16         f[u][ze][lim]+=f[v][ze2][lim2];
17         for(ll j=0; j<=9; ++j)g[u][ze][lim][j]+=g[v][ze2][lim2][j];
18         G[u][ze][lim]+=G[v][ze2][lim2];
19         if(!ze2) {
20             for(ll j=0; j<=i; ++j)g[u][ze][lim][j]+=f[v][ze2][lim2];
21             G[u][ze][lim]+=g[v][ze2][lim2][i+1];
22         }
23     }
24 }
25 ll solve(ll x) {
26     ++ka;
27     for(nbit=0; x; x/=10)bit[++nbit]=x%10;
28     dfs(nbit,1,1);
29     return G[nbit][1][1];
30 }
31 int main() {
32     ll T;
33     for(scanf("%lld",&T); T--;) {
34         scanf("%lld%lld",&a,&b);
35         printf("Case %lld: %lld\n",++ka2,solve(b)-solve(a-1));
36     }
37 }

 

posted @ 2019-08-12 22:04  jrltx  阅读(506)  评论(0编辑  收藏  举报