1 条题解
-
0
自动搬运
来自洛谷,原作者为

BFqwq
青く广がった あの空のように、昙りなく笑えたら あなたに会いたい。搬运于
2025-08-24 22:20:15,当前版本为作者最后更新于2020-04-15 20:56:28,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
看了看题解区的题解,纠结了一下还是把官方题解发出来吧。
感觉做的都比较麻烦,仅有的几个贪心写法的基本也都没给证明。
以下是官方题解。
首先,我们分析输出
-1的情况。容易发现,当 并且 的第一个字符为
1时显然无解,具体证明同样例二。除此以外的情况都是有解的。证明如下:
对于 位数的情况,显然有解。
假设对于 位有解,则对于 位一定有解。
假设 满足前位的一个数为 ,
则只需证明 中必有一个数为 的倍数,且必有一个不为 的倍数。
熟知对于任意正整数 ,相邻的 个正整数中,必有 个数为 的倍数, 个数不为 的倍数。
由于 , 为 个相邻的整数,
故它们中必定有一个数为 的倍数, 个不为 的倍数。
故在接下来的讨论中排除无解的情况。
Subtask 1:
由于 是正整数,在字符串长度为 位的情况下,如果输入的串是
0,则 显然是最小的答案。如果输入的串是 ,则显然直接输出 是最小的,因为 的最小倍数就是 本身。
Subtask 2:
对于 为两位数的情况,我们可以选择直接打表,直接算出每种可能的对应最小解。
我们也可以采用枚举所有两位数逐个判断的方式。
当我们判断某一个数是否符合条件时,我们通过除以 的方式得到其第一位,并判断其是否整除 。
如果第一位符合条件,我们再直接判断其是否整除 以判断前 位是否满足条件。
Subtask 3:
与上面的做法相似,直接枚举所有 位数。
不同的是对于每一个数我们要判断 次。
我们通过除以 得到其第一位,通过除以 得到其前两位构成的数,以此类推。
对于每个数,逐一判断。先分离其第一位判断是否满足条件,若满足则分离前两位,以此类推。
由于 位数一共只有 个,因此我们只需要经过不超过 次枚举就可以找到符合条件的数。
Subtask 4:
要判断一个数是否是 的倍数只需要判断最后一位是否为 的倍数 。
所以我们可以考虑从高位开始往后添加数字。
如果某一位是
1,则我们需要添加的数字是 中的一个。本着最小的原则,我们选择 。同理,如果某一位是
0则我们选择添加一个 。另外,如果字符串的第一位是
1,则我们需要进行特判。
Subtask 5:
考虑延续上面的做法,从高位往后添加数字。
由于我们是在高位上添加的,因此我们只需保证我们添加的数字最小,就一定是最优的。
对于第一位,如果第一位的字符是
0则我们添加 最优,否则第一位添加 最优。然后对于后面的每一位,设我们当前的数是 ,添加的数是 ,则得到的数是 。
由于 只有十种可能性,分别枚举尝试,选取最小的加到数的尾端。
另外,由于 过大,无法直接记录,故每添加一个数后对 取模,然后输出时以字符串的方式输出。
以下是 std 代码。
#include <bits/stdc++.h> using namespace std; char c[100005],n[100005]; int a,b; int now; int main(){ cin>>a>>b>>c; if(c[0]=='0')n[0]='1',now=1; else{ if(a==10){ puts("-1"); return 0; } else n[0]=a+'0'; }; for(int i=1;i<b;i++){ now*=10; for(int j=0;j<=9;j++) if((now+j)%a==0&&c[i]=='1'||(now+j)%a!=0&&c[i]=='0'){ now+=j; now%=a; n[i]=j+'0'; break; } } cout<<n; return 0; }
- 1
信息
- ID
- 5153
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 3
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者