题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1026
很基础的数位DP题,很早之前我就尝试做这题,不过当时我被这题吓死了,现在回过头做这题,感觉简单多了。
做这个题时我想到了POJ一道类似的组合数学的题,同样是按数位统计,有异曲同工之妙。
题目要求[a,b]区间上的windy数个数,我们可以转化成求[1,a]上的windy数个数-[1,b-1]上的windy数个数。题目转化成了求[1,x]上的windy数个数,我们就写个函数cal(x)。另外我们用w[i][j]表示长度为i的数字,最高位为j(注意j可以为0)所组成的windy数个数。很容易推导出公式w[i][j]=Σw[i-1][k],0<=k<=9,|k-j|>=2。这个问题处理完后,就是按位统计的问题了。(1)首先我们统计出长度小于x的windy数个数,(2)然后再统计出长度等于x,最高位数字小于x的最高位数字的windy数个数,(3)再从次高位到个位逐位按照类似步骤(2)的方法统计即可。为了避免前导零的情况,最高位统计时不能将w[i][0]算进去。
网上很多人从低位到高位的方法进行统计,太复杂了,还要讨论,真的不如从高位到低位统计来得方便,囧。
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <algorithm> #define INF 0x3f3f3f3f using namespace std; typedef long long int LL; int primes[]={0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29}; //质数打表 LL n,ans,cnt; //cnt=约数个数最大值,ans=约数个数取最大值时的最小的数字 void DFS(LL num,LL maxP,int now,int nowcnt) //num=当前乘积得到的数,maxp=下一个质数最大的幂,now=当前状态下使用的质数下标,nowcnt=当前数约数个数 { if(nowcnt>cnt||nowcnt==cnt&&num<ans) { cnt=nowcnt; ans=num; } if(now>10) return; //取的质数个数太多了,已经超出了n的范围,不必继续搜索了 LL nownum=num; for(int i=1;i<=maxP;i++) //枚举下一个质因数的幂 { nownum*=(LL)primes[now]; if(nownum>n) return; DFS(nownum,i,now+1,nowcnt*(i+1)); } } int main() { scanf("%lld",&n); ans=1,cnt=1; DFS(1,INF,1,1); printf("%lld\n",ans); return 0; }