1 条题解

  • 0
    @ 2025-8-24 22:20:25

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Silence_water
    天天向上,追逐梦想

    搬运于2025-08-24 22:20:25,当前版本为作者最后更新于2021-06-23 16:25:44,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题目传送门


    本题巨大的数据范围仿佛在告诉我们这是一道数位 DP,但是在阅读完题面后却发现自己束手无措。

    于是开始写无脑暴力,枚举每个数,然后求位数积,判断。这显然是一种偏离正解的方法,无法进一步进行优化。

    换一种想法,如果枚举数不可行,就枚举位数积。记 SSxx 的位数积,显然对于相同的 SS 会对应多个 xx。如果通过枚举每一位上的数来确定 SS,无异于暴力。因此考虑两种枚举 SS 方法:

    1. 枚举 SS 中每个数字出现的个数。

      如果直接枚举出现次数,相当于把 1818 个位置放进 1010 个框,总情况数为 C279=4686825\mathrm{C_{27}^{9}=4686825},无法再继续进行统计对应 xx 的个数,必然超时。

      考虑优化。一个较为显然的结论就是 SxS\le x。又 1AB10181\le A\le B\le 10^{18},所以 S×x1018S\times x\le 10^{18},从而推出 S109S\le 10^9

      还有一个结论就是,如果 xx 中某一数位上的数为 00,那么 S×x=0<ABS\times x=0<A\le B,一定不存在于 [A,B][A,B] 内。

      因此我们只需考虑把 99 个位置放进 99 个框,总情况数就减为 C178=24310\mathrm{C_{17}^8=24310},使得后续的统计成为可能。

    2. 枚举 SS2,3,5,72,3,5,7 四个质数出现的个数。

      由于 SS 必然是由 090-9 这些数的幂相乘而得的,在第 11 种方法中我们已经得出 00 毫无作用。因此剩下的数除 11 以外在分解质因数后一定是由上述四个质数组成,从而可以推出 SS 可以表示成 2a×3b×5c×7d2^a\times 3^b\times 5^c\times 7^d 的形式的。(a,b,c,dN\mathrm{a,b,c,d\in N}

      又因为 S109S\le 10^9,因此 a29a\le 29b18b\le 18c12c\le 12d10d\le 10

      通过相应枚举代码可以得出满足 S109S\le 10^9 的四元组 (a,b,c,d)(a,b,c,d) 的个数为 51945194 种,为后续统计留了较多的时空。

    这里着重讲解第 22 种枚举方法后的统计。

    首先通过 S,A,BS,A,B 我们可以得知 xx 的范围 LLRR

    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 来求得在 [L,R][L,R] 中满足条件的 xx 的个数。

    设计状态 dp[pos][cnt[0]][cnt[1]][cnt[2]][cnt[3]]\mathrm{dp[pos][cnt[0]][cnt[1]][cnt[2]][cnt[3]]},其中 pos\mathrm{pos} 表示当前数位,cnt[03]\mathrm{cnt[0-3]} 分别表示还需填入的 2,3,5,72,3,5,7 的数量。

    注意 00 对答案的干扰。除了作为前导零以外,为了与上面枚举过程相契合,我们不能在数位上填 00

    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;
    

    注意 191-9 每个数的组成,如 6=2×36=2\times 3,那么填入 66 就会对应地消耗 11221133。对应关系如下:

    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
    

    统计部分要求无最高位限制和前导零。如果所有数位填完后,还要检查是否 44 个质数都已填完。相应部分如下:

    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;
    

    本题讲解至此就告一段落了,上述代码块中个别函数请读者自行完成,如有疑问请评论提出,欢迎指正。

    • 1

    信息

    ID
    5443
    时间
    1000ms
    内存
    63MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者