题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555
数位DP专题:http://blog.csdn.net/chy20142109/article/details/50930004
题意:在n的范围内有多少含“49”的数。
思路:简单数位DP,可以直接递推处理不含49的数,算出来用n减。也可以dfs含“49”的数,或dfs不含“49”的数,用n去减。
递推处理再统计
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <utility>
using namespace std;
#define rep(i,j,k) for (int i=j;i<=k;i++)
#define Rrep(i,j,k) for (int i=j;i>=k;i--)
#define Clean(x,y) memset(x,y,sizeof(x))
#define LL __int64
#define inf 0x7fffffff
#define mod %100000007
LL n;
int T;
LL dp[20][10];
void init()
{
Clean(dp,0);
rep(i,0,9) dp[1][i] = 1;
rep(i,2,19)
rep(j,0,9)
rep(k,0,9)
if ( j == 4 && k == 9 ) continue;
else dp[i][j]+=dp[i-1][k];
}
LL cal(LL x)
{
LL ans = 0;
int bit[20];
int len = 0;
Clean(bit,0);
while(x)
{
bit[++len] = x % 10;
x/=10;
}
rep(i,0,bit[len]-1) ans+=dp[len][i];
Rrep(i,len-1,1)
{
rep(j,0,bit[i]-1)
if ( bit[i+1] == 4 && j == 9 ) continue;
else ans+=dp[i][j];
if ( bit[i+1] == 4 && bit[i] == 9 ) break;
}
bool can = false;
rep(i,1,len-1)
if ( bit[i] == 9 && bit[i+1] == 4 ) can = true;
if ( !can ) ans++;
return n - ans;
}
int main()
{
init();
cin>>T;
while(T--)
{
scanf("%I64d",&n);
printf("%I64d\n",cal(n));
}
return 0;
}
直接求含"49"的个数
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <utility>
using namespace std;
#define rep(i,j,k) for (int i=j;i<=k;i++)
#define Rrep(i,j,k) for (int i=j;i>=k;i--)
#define Clean(x,y) memset(x,y,sizeof(x))
#define LL long long
#define ULL unsigned long long
#define inf 0x7fffffff
#define mod %100000007
LL dp[20][3];
// 0 不以4结尾
// 1 以4结尾
// 2 含49
int digit[20];
LL dfs( int k , int id , bool flag )
{
if ( k == 0 ) return id == 2; //是否含“49”
int ed = flag?digit[k]:9;
LL ans = 0;
if ( !flag && dp[k][id]!=-1 ) return dp[k][id];
rep(i,0,ed)
{
int next = id;
if ( id == 0 && i == 4 ) next = 1; //之前不以4结尾,现在以4结尾
if ( id == 1 && i != 4 ) next = 0;
if ( id == 1 && i == 9 ) next = 2; //以49结尾
ans+=dfs( k-1 , next , flag && i == ed );
}
if ( !flag ) dp[k][id] = ans;
return ans;
}
LL cal(LL x)
{
int len = 0;
while( x )
{
digit[++len] = x % 10;
x /= 10;
}
return dfs( len , 0 , 1 );
}
int T;
LL x;
int main()
{
Clean(dp,-1);
cin>>T;
while(T--)
{
scanf("%I64d",&x);
printf("%I64d\n",cal(x));
}
return 0;
}
求不含“49”的个数,再用n去减
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <utility>
using namespace std;
#define rep(i,j,k) for (int i=j;i<=k;i++)
#define Rrep(i,j,k) for (int i=j;i>=k;i--)
#define Clean(x,y) memset(x,y,sizeof(x))
#define LL long long
#define ULL unsigned long long
#define inf 0x7fffffff
#define mod %100000007
int T;
LL n;
LL dp[20][2];
int digit[20];
LL dfs(int k , bool f , bool flag)
{
if ( k == 0 ) return 1;
if ( !flag && dp[k][f] != -1 ) return dp[k][f];
int ed = !flag?9:digit[k];
LL ans = 0;
rep(i,0,ed)
{
if ( !f && i == 9 ) continue;
ans+=dfs( k-1 , (i==4)?0:1 , flag && i == ed );
}
if ( !flag ) dp[k][f] = ans;
return ans;
}
LL cal(LL x)
{
int len = 0;
LL temp = x;
while(x)
{
digit[++len] = x % 10;
x /= 10;
}
return temp - dfs(len,1,1) + 1; //dfs把0也算上了,所以减多了要加回来
}
int main()
{
Clean(dp,-1);
cin>>T;
while(T--)
{
scanf("%I64d",&n);
printf("%I64d\n",cal(n));
}
return 0;
}