标签:sam else font col print 代码 BMI 状态 遇到
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 54005 Accepted Submission(s): 20682
Solution:
话说讲了两星期的数位$DP$了,入坑已久,一直没去填坑(~妄想着打表出奇迹~)。
今天高三二模,学长学姐高考前最后一次模考了,虽然有点喊口号,但我还是想说“高三加油!麓山必胜!”。然后心血来潮,早上$6:30$跑到机房刚数据结构(然而没刚出),忽觉有坑没填,于是打了打数位板子题。
数位$DP$,其实并不难(思路好简单啊),我们只是换个姿态在打暴力,但套上了记忆化使其大大优化而已。
普通的模拟水分,一般就是在一段范围内枚举每个数,将其每位拆开,然后判断是否符合条件,计数就$OK$了(但是这样显然没啥规律可循,状态无法确定,难以记忆化)。
于是我们换个方式,首先可以利用差分的思想,区间$[l,r]$中满足条件的数的个数$=$区间$[0,r]$满足条件的个数$-$区间$[0,l-1]$中满足条件的个数(这很显然)。然后我们考虑从高位往低位枚举$0-9$判断是否可行,当数位到了$0$位时说明可行,那么对于$[0,n]$这个区间,每一位都会有个限制$limit$(不能完全枚举$0-9$中的每一个数)。举个栗子:$n=345$,枚举百位时显然只能从$0-3$中选,然后当百位为$3$时枚举十位就只能从$0-4$中选(百位为$0,1,2$时,十位就可以从$0-9$枚举啦)。
粗略的讲下思路,我们定义状态$f[i][j],i\in[0,8],j=0/1$,表示到了第$i$位,前一位为$j$的方案数($j=0$表示前一位不为$6$,$j=1$表示前一位不为$6$,状态视题目而定,尽量保证正确性下简化!),那么对于所有不受限制的情况都记录状态,事实证明优化贼快~。
代码:
1 #include<bits/stdc++.h> 2 #define il inline 3 #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) 4 using namespace std; 5 int f[20][3],cnt,n,m,ans,p[20]; 6 il int dfs(int pos,int lst,int sta,int limit){ 7 if(!pos)return 1; 8 if(!limit&&f[pos][sta]!=-1)return f[pos][sta]; 9 int up=limit?p[pos]:9,tmp=0; 10 For(i,0,up) 11 if((lst==6&&i==2)||i==4)continue; 12 else tmp+=dfs(pos-1,i,i==6,limit&&i==p[pos]); 13 if(!limit)f[pos][sta]=tmp; 14 return tmp; 15 } 16 il int solve(int x){ 17 cnt=0; 18 while(x){ 19 p[++cnt]=x%10; 20 x=x/10; 21 } 22 return dfs(cnt,-1,0,1); 23 } 24 il int gi(){ 25 int a=0;char x=getchar(); 26 while(x<‘0‘||x>‘9‘)x=getchar(); 27 while(x>=‘0‘&&x<=‘9‘)a=(a<<3)+(a<<1)+x-48,x=getchar(); 28 return a; 29 } 30 int main(){ 31 while(1){ 32 n=gi(),m=gi(); 33 if(!n&&!m)return 0; 34 memset(f,-1,sizeof(f)); 35 printf("%d\n",solve(m)-solve(n-1)); 36 } 37 return 0; 38 }
标签:sam else font col print 代码 BMI 状态 遇到
原文地址:https://www.cnblogs.com/five20/p/9091597.html