hdu 4352 XHXJ's LIS
题意:
先定义一个数的power value,把这个数看成一个字符串,他的最长上升子序列的长度就是他的power value,求某个区间内power value等于k的数的个数。
解法:
很显然要数位DP,先考虑LIS的nlogn解法,我们用dp[len]记录LIS长度为len时的最后一个数的大小,然后不断更新这些值,让每一个值都尽可能小,比如我现在的LIS是1 2 4 6,这时候下一个数是3,那么我们就要更新成1 2 3 6,让前面的数尽可能的小,这样就是为了能让后面的数有更多的机会被加入。
同理,因为数字只有10个,我们可以状态压缩,记录每个数字是否出现在当前的LIS中,然后根据这个状态,用前面的办法转移就行了。
dp[len][number][mask]记录第len位数字是number当前LIS的状态是mask的答案。状态转移可以预处理出来
1 #include<cstdio> 2 #include<cstring> 3 #include<bitset> 4 #include<cstdlib> 5 #include<cmath> 6 #include<iostream> 7 #include<string> 8 #include<vector> 9 #include<queue> 10 #include<deque> 11 #include<set> 12 #include<map> 13 #include<algorithm> 14 using namespace std; 15 typedef long long ll; 16 const int N = 20; 17 ll dp[N][10][1<<10][11]; 18 int hash[1<<10]; 19 int next[1<<10][10]; 20 int bit[N],K; 21 int go(int mask,int number){ 22 int pos = -1; 23 for(int i = number;i <=9;i++) 24 if(mask & (1<<i)){ 25 pos = i; 26 break; 27 } 28 if(pos == -1)mask |= 1<<number; 29 else{ 30 mask ^= 1<<pos; 31 mask |= 1<<number; 32 } 33 return mask; 34 } 35 void init(){ 36 memset(dp,-1,sizeof(dp)); 37 for(int i=0;i<1<<10;i++){ 38 hash[i] = 0; 39 for(int j=0;j<10;j++) 40 if(i&(1<<j))hash[i]++; 41 } 42 for(int i = 0;i < 1<<10;i++) 43 for(int j = 0;j < 10;j++) 44 next[i][j] = go(i,j); 45 for(int i = 0;i < 15;i++){ 46 // cout<<"cur "; 47 // cout<<(bitset<10>)i<<endl; 48 for(int j=0;j<10;j++){ 49 // cout<<"j = "<<j<<" "<<(bitset<10>)next[i][j]<<endl; 50 } 51 } 52 } 53 ll dfs(int pos,int number,int mask,bool isZero,bool flag){ 54 if(pos == 0)return hash[mask] == K; 55 if(flag && ~dp[pos][number][mask][K])return dp[pos][number][mask][K]; 56 ll ans = 0; 57 int u = flag ? 9:bit[pos]; 58 for(int d = 0;d <= u;d++){ 59 if(isZero && d == 0)ans += dfs(pos-1,d,0,1,flag || d < u); 60 else{ 61 ans += dfs(pos-1,d,next[mask][d],0,flag || d < u); 62 } 63 } 64 if(flag)dp[pos][number][mask][K] = ans ; 65 return ans; 66 } 67 ll solve(ll n){ 68 int len = 0; 69 while(n){ 70 bit[++len] = n % 10; 71 n /= 10; 72 } 73 return dfs(len,0,0,1,0); 74 } 75 int main(){ 76 init(); 77 ll L,R; 78 int T;cin >> T; 79 for(int cas = 1;cas <= T;cas++){ 80 cin >> L >> R >> K; 81 cout<<"Case #"<<cas<<": "<<solve(R) - solve(L - 1)<<endl; 82 } 83 return 0; 84 }