题解:P13233 [GCJ 2015 Finals] Costly Binary Search

· · 题解

题解:P13233 [GCJ 2015 Finals] Costly Binary Search

:::warning{open} 本文使用了 AI 进行了润色,我保证我的贡献严格大于 AI。 :::

思路

$f2_{w,j}$ 为当状态为 $w$ 时,从字符串第 $j$ 位向右能到达的最大下标。 接下来我们对于每一个 $i$ 循环一遍。不难发现当且仅当有 $f1_{i,1} = n$ 时,状态 $i$ 是答案,此时输出即可。 接下来我们分为三步。 1. 继承上一个状态的信息。其实就是打擂台,把上一次的信息和这一次的作比较然后看那个更优。 ```cpp for(int j=1;j<=n;j++){ f1[w][j]=min(f1[w][j],f1[l][j]); f2[w][j]=max(f2[w][j],f2[l][j]); } ``` 2. 更新左右边界的信息。这里很显然。 ```cpp for(int j=n-1;j>=1;j--){ f1[w][j]=min(f1[w][j],f1[w][j+1]); } for(int j=1;j<n;j++){ f2[w][j]=max(f2[w][j],f2[w][j-1]); } ``` 3. 状态转移,生成新的状态。先计算新状态 $g=(w+s_j)\mod 10$。然后更新 $f1_{g,r}$ 和 $f2_{g,l}$。 ```cpp for(int j=1;j<=n;j++){ int g=(w+s[j]-'0')%10; int l=f1[w][j-1],r=f2[w][j+1]; f1[g][r]=min(f1[g][r],l); f2[g][l]=max(f2[g][l],r); } ``` 这样我们就做完了。 ### 代码 ![](https://youke.xn--y7xa690gmna.cn/s1/2026/02/01/697f5ef6c7813.webp) ```cpp line-numbers #include<bits/stdc++.h> using namespace std; typedef long long ll; typedef double db; typedef long double ldb; int T,n; char s[1000005]; int f1[10][1000005],f2[10][1000005]; int main(){ scanf("%d",&T); for(int cs=1;cs<=T;cs++){ scanf("%s",s+1); n=strlen(s+1); for(int i=0;i<=9;i++){ for(int j=0;j<=n+1;j++){ f1[i][j]=j+1,f2[i][j]=j-1; } } for(int i=1;i<=n;i++){ f1[s[i]-'0'][i]=i; f2[s[i]-'0'][i]=i; } for(int i=0;1;i++){ int w=i%10; if (f2[w][1]==n){ printf("Case #%d: %d\n",cs,i); break; } int l=(i+9)%10; if (i){ for(int j=1;j<=n;j++){ f1[w][j]=min(f1[w][j],f1[l][j]); f2[w][j]=max(f2[w][j],f2[l][j]); } } for(int j=n-1;j>=1;j--){ f1[w][j]=min(f1[w][j],f1[w][j+1]); } for(int j=1;j<n;j++){ f2[w][j]=max(f2[w][j],f2[w][j-1]); } for(int j=1;j<=n;j++){ int g=(w+s[j]-'0')%10; int l=f1[w][j-1],r=f2[w][j+1]; f1[g][r]=min(f1[g][r],l); f2[g][l]=max(f2[g][l],r); } } } return 0; } ```