题解 P6400
Silence_water · · 题解
题目传送门
本题巨大的数据范围仿佛在告诉我们这是一道数位 DP,但是在阅读完题面后却发现自己束手无措。
于是开始写无脑暴力,枚举每个数,然后求位数积,判断。这显然是一种偏离正解的方法,无法进一步进行优化。
换一种想法,如果枚举数不可行,就枚举位数积。记
-
枚举
S 中每个数字出现的个数。如果直接枚举出现次数,相当于把
18 个位置放进10 个框,总情况数为\mathrm{C_{27}^{9}=4686825} ,无法再继续进行统计对应x 的个数,必然超时。考虑优化。一个较为显然的结论就是
S\le x 。又1\le A\le B\le 10^{18} ,所以S\times x\le 10^{18} ,从而推出S\le 10^9 。还有一个结论就是,如果
x 中某一数位上的数为0 ,那么S\times x=0<A\le B ,一定不存在于[A,B] 内。因此我们只需考虑把
9 个位置放进9 个框,总情况数就减为\mathrm{C_{17}^8=24310} ,使得后续的统计成为可能。 -
枚举
S 中2,3,5,7 四个质数出现的个数。由于
S 必然是由0-9 这些数的幂相乘而得的,在第1 种方法中我们已经得出0 毫无作用。因此剩下的数除1 以外在分解质因数后一定是由上述四个质数组成,从而可以推出S 可以表示成2^a\times 3^b\times 5^c\times 7^d 的形式的。(\mathrm{a,b,c,d\in N} )又因为
S\le 10^9 ,因此a\le 29 ,b\le 18 ,c\le 12 ,d\le 10 。通过相应枚举代码可以得出满足
S\le 10^9 的四元组(a,b,c,d) 的个数为5194 种,为后续统计留了较多的时空。
这里着重讲解第
首先通过
void count(ll mul,int fac)
{
if(mul>B/mul)return;
if(fac==4)
{
ll L=(A-1ll)/mul+1ll;
ll R=B/mul;
ans+=solve(R)-solve(L-1);
return;
}
count(mul,fac+1);
cnt[fac]++;
count(mul*c[fac],fac);
cnt[fac]--;
}
然后考虑通过数位 DP 来求得在
设计状态
注意
ll ans=0;
if(lead)ans+=dfs(pos-1,limit&&a[pos]==0,true);
int up=limit?a[pos]:9;
for(int i=1;i<=up;i++)
{
if(!enough(i))continue;
work(i,-1);
ans+=dfs(pos-1,limit&&i==up,false);
work(i,1);
}
if(!limit&&!lead)DP=ans;
return ans;
注意
const int dig[10][4]={{0,0,0,0},//0位置无实际意义,无需理会
{0,0,0,0},{1,0,0,0},{0,1,0,0},//1 2 3
{2,0,0,0},{0,0,1,0},{1,1,0,0},//4 5 6
{0,0,0,1},{3,0,0,0},{0,2,0,0}};//7 8 9
统计部分要求无最高位限制和前导零。如果所有数位填完后,还要检查是否
if(pos==0)return (!lead)&&check();
ll &DP=dp[pos][cnt[0]][cnt[1]][cnt[2]][cnt[3]];
if(!limit&&!lead&&DP!=-1)return DP;
本题讲解至此就告一段落了,上述代码块中个别函数请读者自行完成,如有疑问请评论提出,欢迎指正。