1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <string.h> 5 #include <algorithm> 6 #define LL __int64 7 using namespace std; 8 9 LL dp[25][1<<10][11]; 10 LL aa,bb; 11 int a[30],k; 12 /*这道题的难点就在于DP的状态表示了,确实是这样的。DP【pos】【state】【K】,pos表示当前的数位,state表示当前的LIS的状态,K 13 表示要求的K长度。那个DFS就不解释了,都成模板了。而对于state的转移,是用二进制表示当前状态,因为最长的 14 序列就是0~9十个数表示,所以有十位的二进制。例如12456的上升序列,下一次出现3,则可表示为12356,至于转移,要联系nlogn解法的 15 LIS来看了 */ 16 int getnews(int x,int s){ 17 for(int i=x;i<10;i++) 18 if(s&(1<<i))return (s^(1<<i))|(1<<x); 19 return s|(1<<x); 20 } 21 int getnum(int s){ 22 int ret=0; 23 while(s) 24 { 25 if(s&1)ret++; 26 s>>=1; 27 } 28 return ret; 29 } 30 31 LL dfs(int len,int st,bool zero,bool flag){ 32 if(len==0) return getnum(st)==k; 33 if(!flag&&dp[len][st][k]!=-1) 34 return dp[len][st][k]; 35 int en=flag?a[len]:9; 36 LL ans=0; 37 for(int i=0;i<=en;i++){ 38 ans+=dfs(len-1,(zero&&i==0)?0:getnews(i,st),zero&&i==0,flag&&i==en); 39 } 40 if(!flag) dp[len][st][k]=ans; 41 return ans; 42 } 43 44 LL cal(LL n){ 45 LL tmp=n; 46 int len=0; 47 while(tmp){ 48 a[++len]=(int)(tmp%10); 49 tmp/=10; 50 } 51 return dfs(len,0,true,true); 52 } 53 54 int main(){ 55 memset(dp,-1,sizeof(dp)); 56 int T,t=0; 57 scanf("%d",&T); 58 while(++t<=T){ 59 scanf("%I64d%I64d%d",&aa,&bb,&k); 60 printf("Case #%d: %I64d\n",t,cal(bb)-cal(aa-1LL)); 61 } 62 return 0; 63 }
时间: 2024-11-10 14:00:00