码迷,mamicode.com
首页 > 其他好文 > 详细

hdu 4352

时间:2015-02-01 13:24:12      阅读:191      评论:0      收藏:0      [点我收藏+]

标签:

搞半天才懂

求区间L到R之间的数A满足A的的数位的最长递增序列的长度为K的数的个数。

s是各数字状态压缩后的

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define maxn 205
typedef long long ll;
using namespace std;

ll n,m,ans,tot,le,ri,k;
ll dig[20],dp[20][1<<11][11];

ll getstate(ll s,ll u,ll& xx)  // 状态转移
{
  ll i,ss;
  for(i=u;i<10;i++)
  {
    if(s&(1<<i)) break ;
  }
  if(i<10)
  {
    ss=s^(1<<i);
    ss=ss^(1<<u);
  }
  else
  {
    xx++;
    ss=s^(1<<u);
  }
  return ss;
}
ll dfs(ll pos,ll s,ll len,ll flg,ll lead) // 当前位 LIS状态 LIS长度 上界标志 前导0标志
{
  if(pos==0)
  {
    if(len==k) return 1;
    return 0;
  }
  if(!flg&&dp[pos][s][k]!=-1) return dp[pos][s][k];
  ll i,j,t,ed,res=0;
  if(flg) ed=dig[pos];
  else ed=9;
  for(i=0;i<=ed;i++)
  {
    ll ss,nlen=len;
    if(lead==0&&i==0) ss=0;
    else ss=getstate(s,i,nlen);
    t=dfs(pos-1,ss,nlen,flg&&i==ed,lead||i!=0);
    res+=t;
  }
  if(!flg) dp[pos][s][k]=res;
  return res;
}
ll solve(ll x)
{
  ll i,j,t=x;
  tot=0;
  while(t)
  {
    dig[++tot]=t%10;
    t/=10;
  }
  ll res=dfs(tot,0,0,1,0);
  return res;
}
int main()
{
  ll i,j,t,test=0;
  memset(dp,-1,sizeof(dp));
  scanf("%I64d",&t);
  while(t--)
  {
    scanf("%I64d%I64d%I64d",&le,&ri,&k);
    ans=solve(ri)-solve(le-1);
    printf("Case #%I64d: %I64d\n",++test,ans);
  }
  return 0;
}

 

hdu 4352

标签:

原文地址:http://www.cnblogs.com/cnblogs321114287/p/4265368.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!