A*B-dp好题

P2841 A*B-dp好题

题意

给出一个数 \(A\) ,你需要给出一个最小的数 \(B\) ,使得 \(A×B\) 的结果只含有 \(0\)\(1\)

思路

初见

很容易想到枚举结果 \(C\) 的最小值,看看是否满足 \(A×C=B\)。然后。。 \(wa\) 了两个点。。发现 \(long long\) 小了点,换成 \(\_\_int128\) 然后 \(T\) 了,就说蓝题没有这么简单(但已经有 \(80\) 分了)。

思考

由于要求的是最小值,试着贪心,发现:

  1. 得到的结果类似于二进制数,可以考虑一些二进制的优化。
  2. 我们要求满足其是 A 的倍数,这和因数,余数等有关。
发现

二进制优化都是加法,想从因数下手是没辄了。但是余数似乎很有说法。

我们似乎可以将每个 \(100...\) 对 A 取模的余数预处理出来,然后不断从小往大添加,直到满足条件为止。

但是。。。这么贪心好像忽略了不少东西???

完善

如果好不顾虑的贪心,会有 \(1+1=2\) 的情况,但是完全按照 01 串的生成,时间复杂度直接爆炸,我们手动搓一下样例,就会发现在正常扩展时,有很多余数相同的01串。

01 串 (十进制) 模 6 结果
1 1
10 4
11 5
100 4 已出现
101 5 已出现
110 2
111 3
1000 4 已出现
1001 5 已出现
1010 2 已出现
1011 3 已出现
1100 2 已出现
1101 3 已出现
1110 0
1111 1 已出现

而由这些串拓展出的串一定比取模最短的拓展出来长,且拓展出来的模数一定会被更小的串覆盖。

数学点说就是:由于 \(r\) 相同,所以 \(r*10 + (0/1) \mod q\)相等。

所以我们只用记录和拓展不同模数下的最短串,就可以得到结果。

代码

在代码之前先说点细节:

  1. 我们只要对最短的串拓展一次,但是要注意先从小的串开始
  2. 由于扩展是对随机一个可能的串进行的,所以 bfs 是一个不错的选择
#include <bits/stdc++.h>
#define int long long
using namespace std;
constexpr int maxn = 1e4+10;
constexpr int maxm = 1e2+10;

int dp[maxn]; // 存串的id
int ri[maxn]; // 串id对应的dp_id=余数
char s[maxn][maxm];// 存串,其实可以直接存值
int n,idx;
queue<int> q; // 待处理的串的id

void write(__int128 x)
{
    if(x/10>0)
    {
        write(x/10);
    }
    putchar((x%10)^48);
}

signed main()
{
    #ifndef ONLINE_JUDGE
    freopen("cjdl.in","r",stdin);
    freopen("cjdl.out","w",stdout);
    #endif // ONLINE_JUDGE
    scanf("%lld",&n);
    dp[++idx]=1;
    ri[1]=1%n;
    s[1][1]='1';
    q.emplace(1);

    int ans_id;
    while(!q.empty())
    {
        int uid=q.front(); q.pop();
        if(ri[uid]==0)
        {
            ans_id=uid;
            break;
        }
        int r=ri[uid]*10%n;
        if(!dp[r])
        {
            ++idx;
            int i=1;
            for(;s[uid][i];++i)
            {
                s[idx][i]=s[uid][i];
            }
            s[idx][i]='0';
            ri[idx]=r;
            dp[r]=idx;
            q.emplace(idx);
        }
        ++r;
        r%=n;// 记得取模
        if(!dp[r])
        {
            ++idx;
            int i=1;
            for(;s[uid][i];++i)
            {
                s[idx][i]=s[uid][i];
            }
            s[idx][i]='1';
            ri[idx]=r;
            dp[r]=idx;
            q.emplace(idx);
        }
    }

    __int128 x=0;
    __int128 ans=0;
    for(int i=1;s[ans_id][i];++i)
    {
        x=x*10+(s[ans_id][i]^48);
    }
    ans=x/n;

    write(ans);
    putchar(' ');
    write(x);

    return 0;
}
posted @ 2025-11-10 14:55  玖玮  阅读(0)  评论(0)    收藏  举报