题目描述
这两道题是让我们在一个数的范围之内查找给定的一个模式。比如从0000-9999这些字符串当中,删除所有存在49相连的字符串。
算法思路
- 其实我们可以发现,这个时候,这些数就可以看作一些定长字符串的排列。而根据排列组合的知识,这些字符串会有10n个。
- 在对字符串的操作当中,我们一般观察的是其中的首尾元素及其长度,而很少去观察字符串中间的元素。其原因就是观察中间的元素必然会使得我们的解空间进一步加大。
- 在这里,我们采用DP转移函数dp[i][j][k]表示长度为i,起始元素为j的符合(0代表符合条件,1代表不符合条件)的字符串的数目。以4,9为例,我们主要关注这两个特殊的元素。即若长度i-1在向长度为i转移时,如果字符串的首元素分别为4,9。那么合法的字符串也转化为了不合法的字符串。
代码
hdu2089
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define MAXK 10
int n,m;
int dp[11][10][2];
void Init()
{
memset(dp,0,sizeof(dp));
dp[0][0][0] = 1;
int i,j,k;
for(i=1;i<=MAXK;i++){
for(j=0;j<10;j++){
for(k=0;k<10;k++){
dp[i][j][1] += dp[i-1][k][1];
//legal string may transfor to ilegal string
if(j==4 || (j==6 && k==2))dp[i][j][1] += dp[i-1][k][0];
else dp[i][j][0] += dp[i-1][k][0];
}
}
}
}
int Compute(int num)
{
int bitN=0,digit[MAXK],i,j,ans=0;
while(num){
digit[++bitN] = num % 10;
num /= 10;
}
digit[bitN+1] = 0;
for(i=bitN;i>0;i--){
for(j=0;j<digit[i];j++){
if(digit[i+1]==6 && j==2)continue;
//avoid to add ilegal pattern
ans += dp[i][j][0];
}
if(digit[i]==4 || (digit[i+1]==6 && digit[i]==2))
break;
//the ilegal pattern show up
}
return ans;
}
int main()
{
//freopen("input","r",stdin);
Init();
while(scanf("%d%d",&n,&m)!=EOF){
if(!n && !m)break;
//printf("%d %d\n",Compute(n+1),Compute(m));
printf("%d\n",Compute(m+1)-Compute(n));
}
return 0;
}
hdu3555
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define LL unsigned long long
#define MAXK 25
int t;
LL n,dp[26][10][2];
void Init()
{
int i,j,k;
memset(dp,0,sizeof(dp));
dp[0][0][0] = 1;
for(i=1;i<=MAXK;i++){
for(j=0;j<10;j++){
for(k=0;k<10;k++){
dp[i][j][1] += dp[i-1][k][1];
if(j==4 && k == 9)dp[i][j][1] += dp[i-1][k][0];
else dp[i][j][0] += dp[i-1][k][0];
}
}
}
return;
}
void Solve(LL num)
{
LL ans = 0;
LL dis[MAXK],j;
int bitN = 0,i;
bool flag = false;
while(num){
dis[++bitN] = num%10;
num /= 10;
}
dis[bitN+1] = 0;
for(i=bitN;i>0;i--){
for(j=0;j<dis[i];j++){
ans += dp[i][j][1];
if(flag)ans += dp[i][j][0];
}
if(dis[i+1]==4 && dis[i] == 9)
flag = true;
}
printf("%llu\n",ans);
}
int main()
{
scanf("%d",&t);
Init();
while(t--){
scanf("%llu",&n);
Solve(n+1);
}
return 0;
}