题意: 有长度为最多为 1000位的大数,其中某些位是 ?,表示可以是 0 ~ 9 中的任意一个数. 给一个数 n,将所有的 ? 都填上,使得最后满足这个大数是 n 的倍数 (至少1倍),同时最小化这个大数 (不含前导 0)
Analyse:
容易想到的是 dp 做法。dp[i][j] 表示当前到第 i 位,mod n == j 的最小数,转移也并不复杂。
但是问题来了,这个数是一个大数,存不下怎么办。
于是组队的时候来了一个奇特的想法,把这个数当成字符串来写,比较大小的时候直接比较字典序就可以 (到第 i 位的时候长度都一样)。
但是又新增了一个问题,比较字符串字典序的大小 复杂度过不去呀。
然后又来了一种想法:
-
有一个结构体,结构体包含一个string num,和一个 p . 分别表示到第 i 位时这个数是什么,且 n u m % n = = p num \% n == p num%n==p
-
有两个 vector,v1 和 v2,都是存结构体
-
v1 中的每个结构体表示到第 i 位,mod n == p 时 最小的数为 num
-
那么向第 i + 1 位转移时,按 num的值 从小到大 枚举,通过本位的 p 可以算的下一位的 pnext 是多少,如果 pnext 没有出现过,那么直接放进 v2,记录 vis[pnext] = 1。否则不做任何操作 . 处理完一位之后赋值 v1 = v2 即可
-
解释两点: 虽然是按 num的值 从小到大枚举,但是并不需要排序,因为能保证从一开放入的时候就是从小到大的。每一位的状态最多1000个,因为 n 最多 1000,即 mod n == x,x 的情况最多1000
最后的最后,其实怀疑了一下,因为不知道字符串复制的复杂度,所以抱着侥幸的心试了一试,然后就 A了,大概是 600 ms
具体还是参考代码.
Code:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1010;
bool vis[maxn];
char a[maxn];
int p;
struct Pair{
string first;
int second;
};
Pair MP(string a,int b){
return Pair{a,b};
}
vector<Pair> v1,v2; //se: mod
int main(){
scanf("%s %d",a + 1,&p);
v1.reserve(maxn); v2.reserve(maxn);
int n = strlen(a + 1);
if(n > 1) {
if (a[1] == '?') {
for (char i = '1'; i <= '9'; ++i) {
string tmp = ""; tmp += i;
v1.emplace_back(MP(tmp,(i - '0') % p));
}
} else {
string tmp = ""; tmp += a[1];
v1.emplace_back(MP(tmp,(a[1] - '0') % p));
}
for (int i = 2; i <= n; ++i) {
for(int i = 0;i < maxn;++ i) vis[i] = 0;
for(int j = 0;j < v1.size();++ j){
if(a[i] == '?'){
for(char k = '0';k <= '9';++ k){
if(!vis[(v1[j].second * 10 + (k - '0')) % p]){
v2.emplace_back(MP(v1[j].first + k,(v1[j].second * 10 + (k - '0')) % p));
vis[(v1[j].second * 10 + (k - '0')) % p] = 1;
}
}
}
else {
if(!vis[(v1[j].second * 10 + (a[i] - '0')) % p]){
v2.emplace_back(MP(v1[j].first + a[i],(v1[j].second * 10 + (a[i] - '0')) % p));
vis[(v1[j].second * 10 + (a[i] - '0')) % p] = 1;
}
}
}
v1 = v2;
v2.clear();
}
int flag = 0;
for(int i = 0;i < v1.size();++ i){
if(v1[i].second == 0){
cout << v1[i].first << endl;
flag = 1;
break;
}
}
if(!flag) printf("*\n");
}
else {
// if(a[1] == '?') printf("0\n");
// else if((a[1] - '0') % p == 0) printf("%c\n",a[1]);
if(a[1] == '?' && p < 10) printf("%d\n",p);
else printf("*\n");
}
return 0;
}