题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=3555
题意:求给定区间的含有49的数的个数。
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <map>
#include <queue>
#include <algorithm>
using namespace std;
#define LL __int64
LL dp[25][3];
int A[25];
//(0,a]范围内有多少个吉利数
LL calc(LL a)
{
int m = 0;
LL ans = 0;
bool flag = false;
while(a)
{
A[++m] = a%10;
a/=10;
}
A[m+1] = 0;
for(int i=m;i>=1;i--)
{
ans += dp[i-1][2] * A[i];
if(flag)
{
ans += dp[i-1][0] * A[i];
}
else
{
if(A[i]>4) ans += dp[i-1][1];
if(A[i+1] == 4 && A[i] == 9) flag = true;
}
}
//数本身
if(flag) ans++;
return ans;
}
//dp[i][0]:长度<=i的不含49的数的个数
//dp[i][1]:长度为i,且最高位含有9的不含49的数的个数
//dp[i][2]:长度<=i的含有49的数个数
void init()
{
memset(dp,0,sizeof(dp));
dp[0][0] = 1;
for(int i=1;i<=22;i++)
{
dp[i][0] = dp[i-1][0]*10 - dp[i-1][1];
dp[i][1] = dp[i-1][0];
dp[i][2] = dp[i-1][2] * 10 + dp[i-1][1];
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
int t;
LL a;
init();
scanf(" %d",&t);
while(t--)
{
scanf(" %I64d",&a);
LL ans = calc(a);
printf("%I64d\n", ans);
}
return 0;
}
题意:求给定区间范围内的,求相邻数位之差绝对值不小于2的数的个数。
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1026
题意:求给定区间范围内的,求相邻数位之差绝对值不小于2的数的个数。
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <map>
#include <queue>
#include <algorithm>
using namespace std;
int A[12];
int f[12][10];
//f[i][j]代表长度为i,最高位为j的windy数个数
void init()
{
memset(f,0,sizeof(f));
for(int i=0;i<10;i++) f[1][i] = 1;
for(int i=2;i<=10;i++)
{
for(int j=0;j<10;j++)
{
for(int k=0;k<10;k++)
{
if(abs(j-k)>1) f[i][j] += f[i-1][k];
}
}
}
}
//(0,a)范围内的windy数个数
int calc(int a)
{
int m = 0;
while(a)
{
A[m++] = a%10;
a/=10;
}
int ans = 0;
//先处理长度小于m的windy数的个数
for(int i=1;i<m;i++)
{
//题目要求不含前导0
for(int j=1;j<10;j++)
{
ans += f[i][j];
}
}
//长度等于m且最高位和原数不同且小于原数的windy数
for(int j=1;j<A[m-1];j++) ans += f[m][j];
//依次循环将最高位 变为和原数相同
for(int i=m-1;i>=1;i--)
{
for(int j=0;j<A[i-1];j++)
{
if(abs(j-A[i]) > 1) ans += f[i][j];
}
if(abs(A[i] - A[i-1])<=1) break;
}
return ans;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
int a,b;
init();
while(scanf(" %d %d",&a,&b)!=EOF)
{
int ans = calc(b+1) - calc(a);
printf("%d\n",ans );
}
return 0;
}
Hdu 2089 不要62
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2089
求给定区间中不含有62和4的数的个数。
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <map>
#include <queue>
#include <algorithm>
using namespace std;
int dp[10][3];
int A[10];
//(0,a]范围内有多少个吉利数
int calc(int a)
{
int sum = a;
int m = 0;
int ans = 0;
bool flag = false;
while(a)
{
A[++m] = a%10;
a/=10;
}
A[m+1] = 0;
for(int i=m;i>=1;i--)
{
ans += dp[i-1][2] * A[i];
if(flag)
{
ans += dp[i-1][0] * A[i];
}
else
{
if(A[i]>4) ans += dp[i-1][0];
if(A[i+1] == 6 && A[i]>2) ans += dp[i][1];
if(A[i]>6) ans += dp[i-1][1];
if(A[i] == 4 || (A[i+1] == 6 && A[i] == 2)) flag = true;
}
}
//数本身
if(flag) ans++;
return sum - ans;
}
//dp[i][0]:长度<=i的吉利数个数
//dp[i][1]:长度为i,且最高位含有2的吉利数个数
//dp[i][2]:长度<=i的非吉利数个数
void init()
{
memset(dp,0,sizeof(dp));
dp[0][0] = 1;
for(int i=1;i<=8;i++)
{
dp[i][0] = dp[i-1][0]*9 - dp[i-1][1];
dp[i][1] = dp[i-1][0];
dp[i][2] = dp[i-1][0] + dp[i-1][1] + dp[i-1][2] * 10;
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
int a,b;
init();
while(scanf(" %d %d",&a,&b)!=EOF)
{
if(a == 0 && b == 0) break;
int ans = calc(b) - calc(a-1);
printf("%d\n",ans);
}
return 0;
}
Hoj 1983 Beautiful numbers
题目链接:http://acm.hit.edu.cn/hoj/problem/view?id=1983
题意:如果一个数能够被其每个数位的数都整除,那么这个数就叫做美丽数。
基本思路是用:dp[len][mod][lcm]表示<=len的长度中,此数为mod,各数位的最小公倍数为lcm的数的个数来进行记忆化搜索。方法和上一题类似。
但我们发现,len在[1,20]范围内,mod在[1,1^18]范围内,lcm在[1,2520]范围内。所以dp数组肯定超内存。
下面我们来进行内存优化:
假设这个数为a,各个数位的值分别为ai,那么我们发现lcm(ai) | a.
而[1,9]的最小公倍数是2520.那么lcm(ai) | 2520, 所以lcm(ai) | (a%2520).
所以第二维大小我们可以从1^18降到2520,方法是%2520.
现在的dp数组的内存是20*2520*2520,还是很大。
然后我们再考虑:
我们发现某一个数的各个数位的数的最小公倍数最大是2520,而且只能是2520的公约数。而2520的公约数有48个。所以第三维我们只用[50]的空间就行了。
方法是用Hash进行离散化。‘
这样内存就成了20*2520*50,可以拿下这道题目了。
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <map>
#include <queue>
#include <algorithm>
using namespace std;
#define LL long long
LL dp[20][2525][55];
int digit[20];
int hash[2525];
int gcd(int a,int b)
{
if(b == 0) return a;
return gcd(b,a%b);
}
int calc_lcm(int a,int b)
{
return a/gcd(a,b)*b;
}
LL dfs(int pos,int mod,int lcm,bool limit)
{
LL ans = 0;
if(pos<=0) return mod % lcm == 0;
if(!limit && dp[pos][mod][hash[lcm]]!=-1) return dp[pos][mod][hash[lcm]];
int end = limit ? digit[pos] : 9;
for(int i=0;i<=end;i++)
{
ans += dfs(pos-1,(mod*10+i)%2520,i?calc_lcm(lcm,i):lcm,limit && (i==end));
}
if(!limit) dp[pos][mod][hash[lcm]] = ans;
return ans;
}
LL calc(LL a)
{
if(a<0) return 0;
int len = 0;
while(a>0)
{
digit[++len] = a%10;
a/=10;
}
//0也当作其中的一个美丽数,因为两者相减会抵消掉
LL ans = dfs(len,0,1,1);
return ans;
}
void init()
{
memset(dp,-1,sizeof(dp));
int id = 0;
for(int i=1;i*i<=2520;i++)
{
if(2520%i == 0)
{
hash[i] = id++;
if(i*i!=2520) hash[2520/i] = id++;
}
}
//printf("id = %d\n", id);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
init();
int t;
LL x,y;
while(scanf(" %lld %lld",&x,&y)!=EOF)
{
printf("%lld\n",calc(y) - calc(x-1));
}
return 0;
}