1. 程式人生 > >HDU 4352 XHXJ's LIS

HDU 4352 XHXJ's LIS

using getchar() bre cto 更新 stdout res 一個 之間

XHXJ‘s LIS

http://acm.hdu.edu.cn/showproblem.php?pid=4352

題意:

  詢問L~R之間多少個數滿足以下條件:將數字的每一位上的數字寫成一個序列(這個序列每個數不超過10,長度不超過20),然後這個序列的最長上升子序列的長度為k。

分析:

  數位dp。

  這個狀態有點特殊。首先考慮nlogn求最長上升子序列的過程,記錄每長度為k上升子序列中結尾的最小的是誰。那麽可以記錄這個數組,每次轉移更新數組即可。但是直接記錄是空間開不下。但是發現這個題有一個性質:最大長度為10,最大的數字為10,而且是上升的。如果記入一個長度為10的01串。第b位上的,是從頭開始第a個1,表示長度為a的最長上升子序列的結尾最小的數是b。由於是上升的,每個位上只有一個1,而且長度為10,剛好開得下。

  加入一個數後,找到第一個比它大的數,然後去掉這個,加上新加的。

代碼:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<iostream>
 6 #include<cctype>
 7 #include<set>
 8 #include<vector>
 9 #include<queue>
10 #include<map>
11
#define fi(s) freopen(s,"r",stdin); 12 #define fo(s) freopen(s,"w",stdout); 13 using namespace std; 14 typedef long long LL; 15 16 inline LL read() { 17 LL x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch==-)f=-1; 18 for(;isdigit(ch);ch=getchar())x=x*10+ch-0;return x*f;
19 } 20 21 int a[22], tot, k; 22 LL dp[22][(1 << 10) + 5][11]; 23 24 int getnxt(int i,int s) { 25 for (int j=i; j<=9; ++j) 26 if ((1 << j) & s) { s ^= (1 << j); break; } 27 return s | (1 << i); // !!! 28 } 29 int getbit(int x) { 30 int res = 0; 31 while (x) res += (x & 1), x >>= 1; 32 return res; 33 } 34 LL dfs(int x,int sta,bool lim,bool fir) { 35 if (!x) return getbit(sta) == k; 36 if (!lim && dp[x][sta][k] != -1) return dp[x][sta][k]; 37 LL res = 0; 38 int u = lim ? a[x] : 9; 39 for (int i=0; i<=u; ++i) 40 res += dfs(x - 1, fir&&i==0 ? 0 : getnxt(i, sta), lim&&i==a[x], fir&&i==0); 41 if (!lim) dp[x][sta][k] = res; 42 return res; 43 } 44 LL Calc(LL x) { 45 tot = 0; 46 while (x) { 47 a[++tot] = x % 10; 48 x /= 10; 49 } 50 return dfs(tot, 0, 1, 1); 51 } 52 int main() { 53 memset(dp, -1, sizeof(dp)); 54 int T = read(); 55 for (int t=1; t<=T; ++t) { 56 LL L = read(), R = read(); k = read(); 57 printf("Case #%d: ",t); 58 printf("%lld\n", Calc(R) - Calc(L - 1)); 59 } 60 return 0; 61 }

HDU 4352 XHXJ's LIS