[51nod Round 15 B ] 完美消除

  数位DP。

  比较蛋疼的是,设a[i]表示第i位上数字,比方说a[1]<a[2]>a[3],且a[1]==a[3]时,这两位上的数可以放在一起搞掉。

  所以就在正常的f数组里多开一维,表示后面那些位组成的不增的单调栈中,包含的数字集合。

  f[i][j][k][a]表示i位,首位为j,单调栈数字集合为k,最小消除数为a的数字个数。

  从已知往外推好像好写一点。。

  枚举f[i1][j1][k1][a1],再枚举下一个首位j

  若j<j1: f[i1+1][j][ (k1%2^(j+1))|2^j ][ a1+(2^j&k1?0:1) ]+=f[i1][j1][k1][a1];

  若j==j1:f[i1+1][j][k1][a1]+=f[i1][j1][k1][a1];

  若j>j1:  f[i1+1][j][k1+2^j][a1+1]+=f[i1][j1][k1][a1];

  统计答案时,就在记录一下已确定高位的不减单调栈就行了。。。

  很(jiao)显(wan)而(cai)易(fa)见(xian)的是...j那维是没用的,因为j肯定是k的最大位...所以每个k都对应着唯一的j

  反正都交了。。就懒得改了>_<

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #define ll long long
 5 using namespace std;
 6 ll f[19][10][1025][19];
 7 int two[19],one[19];
 8 int i,j,k,n,m,aa;
 9 int s[23],st[23],top;
10 ll L,R;
11 
12 inline void prerun(){
13     register int k1,a1,j;int i1,j1,i;ll now;
14     for(i=one[0]=two[0]=1;i<10;i++)two[i]=two[i-1]<<1,one[i]=one[i-1]<<1|1;
15     for(i=0;i<10;i++)f[1][i][two[i]][i!=0]=1;
16     for(i1=1;i1<18;i1++)
17         for(j1=0;j1<10;j1++)for(k1=two[j1];k1<=one[j1];k1++)for(a1=0;a1<=i1&&a1<=aa;a1++)
18             if(f[i1][j1][k1][a1]){
19                 now=f[i1][j1][k1][a1];
20                 f[i1+1][0][1][a1]+=now;
21                 for(j=1;j<j1;j++)
22                     f[i1+1][j][(k1&one[j])|two[j]][a1+!(k1&two[j])]+=now;
23                 if(j1!=0)f[i1+1][j1][k1][a1]+=now;
24                 for(j=j1+1;j<10;j++)
25                     f[i1+1][j][k1|two[j]][a1+1]+=now;
26             }
27 }
28 inline int calc(int k){
29     register int sm=0,i;
30     for(i=1;i<=top;i++)if((st[i]!=st[i-1]||i==1)&&st[i]>0)
31         if(!(two[st[i]]&k))sm++;
32     return sm;
33 }
34 inline ll get(ll x){
35     if(!x)return 0;
36     ll tmp=x,ans=0;int len=0;register int i,j,k;
37     while(tmp)s[++len]=tmp%10,tmp/=10;
38     for(i=1;i<len;i++)for(j=1;j<=9;j++)for(k=two[j];k<=one[j];k++)
39         ans+=f[i][j][k][aa];
40     for(j=1;j<s[len];j++)for(k=two[j];k<=one[j];k++)
41         ans+=f[len][j][k][aa];
42     int pre=0,tmpa;st[top=1]=s[len];
43     for(i=len-1;i;i--){
44         if(pre>aa)break;
45         for(j=0;j<s[i];j++)
46             for(k=two[j];k<=one[j];k++)
47                 if((tmpa=aa-pre-calc(k))>=0)
48                 ans+=f[i][j][k][tmpa];
49         while(top&&st[top]>s[i])pre+=(st[top]!=st[top-1]||top==1),top--;
50         st[++top]=s[i];
51     }
52     if(pre+calc(0)==aa)ans++;
53     return ans;
54 }
55 int main(){
56     scanf("%lld%lld%d",&L,&R,&aa);
57     prerun();
58     printf("%lld
",get(R)-get(L-1));
59     return 0;
60 }
View Code
原文地址:https://www.cnblogs.com/czllgzmzl/p/5625685.html