题解:P14287 [ICPC 2025 WF] Score Values
Little_Crocodile · · 题解
前言
改题解写法参考了 apple365 和 GPT 的写法。
题意
你初始有一个整数
思路
第一步:考虑哪些分数可以到达
我们先取
我们可以考虑建造
则
因为我们如果
其次由于我们是同余最短路,很明显
所以这个条件是充要条件。
第二步分类讨论
我们设
-
对于
x \le maxx 的数我们直接暴力枚举判断(易得maxx 不会特别大) -
对于
maxx < x \le m 的点可以用数位 DP 后面会详细讲。 -
对于
x > m 那他会变成m 所以需要提前处理0 和m 。
第三步数位 DP
其实只要会模板就行了。
我们可以考虑暴力遍历每个数字(
在数位 DP 的时候我们依然要满足他的
我们定义
然后就是模板了。
复杂度显然合理。
总结
本人自认为该题难点在于转图论变成求同余最短路后的转变限制求得答案。
代码
码风比较猎奇
#include<bits/stdc++.h>
#define int long long
#define PII pair<int,int>
using namespace std;
const int MAXX = 1e3 + 5, MAXK = 1e2 + 5;
int n, m, ans[MAXX], p[MAXX], minn, maxx, cnt[MAXX], dp[20][2][2][2][20][MAXX], a[MAXX], b[MAXX], tot1, tot2, dis[MAXX], vis[MAXX];
priority_queue<PII, vector<PII>, greater<PII> > q;
void add_answer(int x){
memset(cnt, 0, sizeof cnt);
while(x) cnt[x % 10]++, x /= 10; cnt[6] += cnt[9];
for(int i = 0; i <= 9; i++) ans[i] = max(ans[i], cnt[i]);
}
int dfs(int x, int limit, int flag, int vis, int w, int now, int id){
if(x == 0) return (dis[now] != dis[minn + 1]) * w; //需满足可达到条件
if(dp[x][limit][flag][vis][w][now] != -1) return dp[x][limit][flag][vis][w][now];
int num = 0;
for(int i = (flag ? b[x] : 0); i <= (limit ? a[x] : 9); i++){
int tmp = w;
if(id == 0) tmp += (!vis && (i == 0));
else if(id == 6) tmp += (i == 6 || i == 9);
else tmp += (i == id);
num = max(num, dfs(x - 1, limit & (i == a[x]), flag & (i == b[x]), vis & (i == 0), tmp, (now * 10 + i) % minn, id));
} dp[x][limit][flag][vis][w][now] = num;
return num;
}
signed main(){
cin >> m >> n; ans[0] = 1, add_answer(m); minn = LLONG_MAX;
for(int i = 1; i <= n; i++) cin >> p[i], minn = min(minn, p[i]);
memset(dis, 0x3f, sizeof dis), dis[0] = 0, q.push({0, 0});
while(!q.empty()){
int x = q.top().second; q.pop();
if(vis[x]) continue; vis[x] = 1;
for(int i = 1; i <= n; i++){
int y = (x + p[i]) % minn;
if(dis[y] > dis[x] + p[i]) dis[y] = dis[x] + p[i], q.push({dis[y], y});
}
} for(int i = 0; i < minn; i++) if(dis[i] != dis[minn + 1]) maxx = max(maxx, dis[i]);
for(int i = 1; i <= min(maxx, m); i++) if(dis[i % minn] <= i) add_answer(i);
if(maxx < m){
int tmp1 = m, tmp2 = maxx + 1;
while(tmp1) a[++tot1] = tmp1 % 10, tmp1 /= 10;
while(tmp2) b[++tot2] = tmp2 % 10, tmp2 /= 10;
for(int k = 0; k <= 8; k++) memset(dp, -1, sizeof dp), ans[k] = max(ans[k], dfs(tot1, 1, 1, 1, 0, 0, k));
} for(int i = 0; i <= 8; i++) if(ans[i]) cout << i << " " << ans[i] << '\n';
return 0;
}