• [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
  • 相关阅读:
    软工15结对编程练习
    软件工程网络201521123108阅读作业2-提出问题
    软件工程网络15个人阅读作业1(201521123108 余腾鑫)
    java课程设计——算术运算测试个人博客
    java课程设计-算术运算测试
    201521123108《Java程序设计》第14周学习总结
    201521123108 《Java程序设计》第13周学习总结
    个人作业5——软工个人总结
    软工网络15个人作业4——alpha阶段个人总结
    软件工程网络15个人作业3——案例分析(201521123107)
  • 原文地址:https://www.cnblogs.com/czllgzmzl/p/5625685.html
Copyright © 2020-2023  润新知