D – Jumping Takahashi 2(图论、最短路变形)
Problem
有/(N/)个跳床在二维平面上,第/(i/)个跳床的坐标是/(X_i,Y_i/),弹跳力是/(P_i/),你有一个初始能力值/(S/),从一个跳床/(i/)可以跳到另一个跳床/(j/)的条件是/(SP_i/ge |X_i-X_j|+|Y_i-Y_j|/),现在要求你选择一个点起跳,使得可以从这个点跳到其他所有点时的最小的/(S/)
Solve
条件可以从上取整转换,然后每两个点之间就有一个权值。/(/lceil /frac{x}{y} /rceil=/frac{x+y-1}{y}/)
题意转换后就是要给定一个有向图,求从哪个点出发可以到达其他所有点,并且使得经过路径上的最大边最小
由于这是有向图,并且要求从一个点出发可以到达其他点,所以不能直接求最小生成树,利用迪杰斯特拉的思想去对边进行松弛操作即可
Code
package main
import(
"bufio"
."fmt"
"os"
)
func min(a,b int64)int64{
if a>b{
return b
}else{
return a
}
}
func max(a,b int64)int64{
if a>b{
return a
}else{
return b
}
}
func abs(a int64)int64{
if a<0{
return -a
}else {
return a
}
}
func main(){
in:=bufio.NewReader(os.Stdin)
out:=bufio.NewWriter(os.Stdout)
defer out.Flush()
const N int=205
var n int
Fscan(in,&n)
x,y,p:=make([]int64,n+1),make([]int64,n+1),make([]int64,n+1)
for i:=1;i<=n;i++{
Fscan(in,&x[i],&y[i],&p[i])
}
var dist [N][N]int64
for i:=1;i<=n;i++{
for j:=1;j<=n;j++{
dist[i][j]=(abs(x[i]-x[j])+abs(y[i]-y[j])+p[i]-1)/p[i]
}
}
const inf int64=1e18
vis:=make([]bool,n+1)
f:=make([]int64,n+1)
ans:=inf
for s:=1;s<=n;s++{
for j:=1;j<=n;j++{
vis[j]=false
f[j]=inf
}
f[s]=0;
var res int64
for i:=1;i<=n;i++{
x:=-1
for j:=1;j<=n;j++{
if(!vis[j]&&(x==-1||f[j]<f[x])){
x=j
}
}
vis[x]=true
res=max(res,f[x])
for j:=1;j<=n;j++{
f[j]=min(f[j],dist[x][j])
}
}
for i:=1;i<=n;i++{
ans=min(ans,res)
}
}
Fprintln(out,ans)
}
E- Addition and Multiplication 2
Problem
一开始有一个数/(x=0/),现在有/(N/)元,可以进行以下操作若干次:选择一个整数/(i/)(/(1/le i/le 9/)),并且支付/(C_i/)元去把/(x/)替换成/(10x+i/)。求出/(x/)最大可能的值
Solve
一个贪心的思想,对于当前选择的/(i/),肯定越大越好,但会出现一种情况,就是你选择这个大的可能会使得钱减少的比较多,从而损失较多的操作机会,然而一次操作机会可以扩大/(10/)倍,显然多一次操作机会会比当前选择最大的更优。所以考虑在选择当前最大的时候,判断当前的钱数是否会使得操作次数减少,直到找到不会减少的/(i/)为止,此时可以保证较大且不会减少扩大次数。至于如果快速判断当前选择会不会使得操作次数不优,可以利用背包的方法,求出对于每个面值的钱可以操作的最大次数即可。
Code
package main
import(
"bufio"
."fmt"
"os"
)
func max(a,b int)int {
if a>b{
return a
}else{
return b
}
}
func main(){
in:=bufio.NewReader(os.Stdin)
out:=bufio.NewWriter(os.Stdout)
defer out.Flush()
var n int
Fscan(in,&n)
c:=make([]int,10)
for i:=1;i<=9;i++{
Fscan(in,&c[i])
}
f:=make([]int,n+1)
for i:=1;i<=9;i++{
for j:=c[i];j<=n;j++{
f[j]=max(f[j],f[j-c[i]]+1)
}
}
for f[n]>0{
x:=9
for c[x]>n || f[n-c[x]]!=f[n]-1{
x--
}
Fprint(out,x)
n-=c[x]
}
}
F – Teleporter Setting
Problem
给定/(N/)个点/(M/)条边的无向图,但其中一条边的一个端点因为某种原因不知道具体是哪个点,记未知的点为/(0/),假设丢失的点为/(u/),假设/(u/)取/(1,/cdots,N/),对于每种情况求出从/(1/)到/(N/)的最短路,如果不可以抵达,输出/(-1/)
Solve
在原图上求一遍从/(1/)出发的最短路,再求一遍从/(N/)出发的最短路。
记/(d1_i/)为从/(1/)出发到点/(i/)的最短路,/(dn_i/)为从/(n/)出发到点/(i/)的最短路
假设未知点/(u/)取/(i/),那么答案就是/(min(d1_n,d1_0+dn_i,d1_i+dn_0)/),后面可以看做点/(0/)和点/(i/)之间的距离为/(0/)
Code
package main
import (
."fmt"
"bufio"
"os"
)
func min(a ,b int)int{
if a>b{
return b
}else{
return a
}
}
func main(){
in:=bufio.NewReader(os.Stdin)
out:=bufio.NewWriter(os.Stdout)
defer out.Flush()
const inf int=1e9
var n,m int
Fscan(in,&n,&m)
e:=make([][]int,n+1)
for i:=1;i<=m;i++{
var u,v int
Fscan(in,&u,&v)
e[u]=append(e[u],v)
e[v]=append(e[v],u)
}
d1,d2:=make([]int,n+1),make([]int,n+1)
hh,tt:=0,0
q:=make([]int,n+1)
bfs:=func(s int,d []int){
for i := range d{
d[i]=inf
}
hh,tt=0,0
vis:=make([]int,n+1)
q[tt]=s
tt=tt+1
d[s]=0
for hh<tt{
u:=q[hh]
hh=hh+1
if vis[u]>0{
continue
}
vis[u]=1
for _,v := range e[u] {
if d[v]>d[u]+1{
d[v]=d[u]+1
q[tt]=v
tt=tt+1
}
}
}
}
bfs(1,d1)
bfs(n,d2)
for i:=1;i<=n;i++{
res:=min(d1[n],min(d1[0]+d2[i],d1[i]+d2[0]));
if res>=inf{
res=-1
}
Fprint(out,res," ")
}
}
G – Prefix Concatenation(Z-算法、DP)
Problem
洛谷原题(P8112 [Cnoi2021]符文破译)
给定一个串/(T/)和/(S/),问/(S/)是否可以写成/(T/)的若干个前缀相加,若可以,求出最少的前缀个数,否则输出/(-1/)
Solve
/(Z-algorithm/)可以求出字符串/(S/)以下标/(i/)开始的后缀和/(S/)的最长公共前缀
考虑先求出/(S/)的每个后缀与/(T/)的最大前缀,可以令/(A=T+’/#’+S/),使用 1 次/(Z-algorithm/)求出。
然后考虑/(dp/),令/(dp_i/)表示/(S/)的前/(i/)位可以由/(T/)最少的前缀组成的个数。
假设处理到了第/(i/)位,假设第/(i/)位可以匹配的最长前缀为/(k=z[n+1+i]/),那么显然/(dp_i,/cdots,dp_{i+k-1}/)都是相等的,考虑/(i+1/)位,如果/(i+1+z[n+1+i+1]>i+k-1/)了,那么由于/(i+k-1/)后面可能会无法匹配,那么能在前面匹配过来就在前面匹配匹配过来肯定是最好的,所以每次记录一个每次可以匹配到的最远距离来更新即可。
Code
由于 Go 的快读使用bufio
使用虚拟内存过多,这份 go 代码在洛谷上会 MLE。
package main
import(
"bufio"
."fmt"
"os"
)
func min(a,b int)int{
if(a>b){
return b
}
return a
}
func max(a,b int)int{
if(a>b){
return a
}else{
return b
}
}
const N int =1e6+10
const inf int=1e9
var z,dp [N]int
func main(){
in:=bufio.NewReader(os.Stdin)
out:=bufio.NewWriter(os.Stdout)
defer out.Flush()
var s,t []byte
Fscan(in,&s,&t)
n,m:=len(s),len(t)
var a []byte
for i:=0;i<n;i++{
a=append(a,s[i])
}
a=append(a,'#')
for i:=0;i<m;i++{
a=append(a,t[i])
}
// Fprintf(out,"%s",a)
for i,l,r:=1,0,0;i<n+m+1;i++{
if i<=r{
z[i]=min(r-i+1,z[i-l]);
}
for i+z[i]<n+m+1 && a[z[i]]==a[i+z[i]]{
z[i]++
}
if i+z[i]-1>r{
l=i
r=i+z[i]-1
}
}
for i:=0;i<=m;i++{
dp[i]=inf
}
dp[0]=0
var mx int=0
for i:=0;i<m;i++{
x:=dp[i]
if x>m {
continue
}
k:=z[n+i+1]
for j:=mx+1;j<=i+k;j++{
dp[j]=x+1
}
mx=max(mx,i+k)
}
if dp[m]<inf{
Fprintln(out,dp[m])
}else{
Fprintln(out,-1)
}
}
Ex – Dice Sum 2(优化?)
Problem
Solve
Code
原创文章,作者:,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/270567.html