Return to problem list2017-1A Problem C
Solution that only works for the small input
func start() {
var t int
mustReadLineOfInts(&t)
for i := 0; i < t; i++ {
fmt.Fprintf(stdout, "Case #%d: ", i+1)
debug(fmt.Sprintf("Processing case %d", i+1))
best := test()
if best >= 0 {
fmt.Fprintf(stdout, "%d\n", best)
} else {
stdout.WriteString("IMPOSSIBLE\n")
}
}
}
func test() int {
var Hd, Ad, Hk, Ak, B, D int
mustReadLineOfInts(&Hd, &Ad, &Hk, &Ak, &B, &D)
best := -1
maxDebuff := 0
if D != 0 {
maxDebuff = Ak/D + 1
}
currentT := 0
currentDebuff := 0
currentHealth := Hd
lastActionIsCure := false
tBA, buff := optimizeBA(Hk, Ad, B)
debug(fmt.Sprintf("tBA = %v", tBA))
assert(tBA > buff)
for currentDebuff <= maxDebuff {
debug(fmt.Sprintf("currentDebuff = %v, currentHealth = %v", currentDebuff, currentHealth))
cureNeeded := 0
impossible := false
lastActionIsCure = false
healthBeforeBA := currentHealth
for i := 0; i < tBA-1; {
healthAfterThis := currentHealth - attack(Ak, currentDebuff, D)
if healthAfterThis <= 0 {
if lastActionIsCure {
impossible = true
break
} else {
lastActionIsCure = true
cureNeeded++
currentHealth = Hd - attack(Ak, currentDebuff, D)
if currentHealth < 0 {
impossible = true
break
}
}
} else {
lastActionIsCure = false
currentHealth = healthAfterThis
i++
}
}
if impossible {
currentHealth = healthBeforeBA
if currentHealth-attack(Ak, currentDebuff+1, D) >= 0 {
currentT++
currentDebuff++
currentHealth = currentHealth - attack(Ak, currentDebuff, D)
continue
} else if Hd-attack(Ak, currentDebuff, D)-attack(Ak, currentDebuff+1, D) <= 0 {
break
} else {
currentT++
currentHealth = Hd - attack(Ak, currentDebuff, D)
currentDebuff++
currentT++
currentHealth -= attack(Ak, currentDebuff, D)
continue
}
}
thisTurnNumber := currentT + tBA + cureNeeded
debug(fmt.Sprintf("thisTurnNumber = %d", thisTurnNumber))
if best > thisTurnNumber || best == -1 {
best = thisTurnNumber
}
currentHealth = healthBeforeBA
currentDebuff++
currentT++
if currentHealth-attack(Ak, currentDebuff, D) <= 0 {
currentT--
currentDebuff--
if Hd-attack(Ak, currentDebuff, D) <= 0 {
break
} else {
currentT++
currentHealth = Hd - attack(Ak, currentDebuff, D)
currentT++
currentDebuff++
currentHealth -= attack(Ak, currentDebuff, D)
if currentHealth <= 0 {
break
}
}
} else {
currentHealth -= attack(Ak, currentDebuff, D)
}
}
return best
}
func attack(Ak, currentDebuff, D int) int {
if currentDebuff*D >= Ak {
return 0
} else {
return Ak - currentDebuff*D
}
}
func optimizeBA(Hk, Ad, B int) (tBA, buff int) {
if B == 0 {
return int(math.Ceil(float64(Hk) / float64(Ad))), 0
}
b := sort.Search(Hk/B+1, func(b int) bool {
thisB := b + int(math.Ceil(float64(Hk)/float64(Ad+B*b)))
nextB := b + 1 + int(math.Ceil(float64(Hk)/float64(Ad+B*(b+1))))
return nextB >= thisB
})
debug(fmt.Sprintf("b = %d", b))
return b + int(math.Ceil(float64(Hk)/float64(Ad+B*b))), b
}
func start() {
var t int
mustReadLineOfInts(&t)
for i := 0; i < t; i++ {
fmt.Fprintf(stdout, "Case #%d: ", i+1)
debug(fmt.Sprintf("Processing case %d", i+1))
best := test()
if best >= 0 {
fmt.Fprintf(stdout, "%d\n", best)
} else {
stdout.WriteString("IMPOSSIBLE\n")
}
}
}
func test() int {
var Hd, Ad, Hk, Ak, B, D int
mustReadLineOfInts(&Hd, &Ad, &Hk, &Ak, &B, &D)
best := -1
maxDebuff := 0
if D != 0 {
maxDebuff = Ak/D + 1
}
currentT := 0
currentDebuff := 0
currentHealth := Hd
lastActionIsCure := false
tBA, buff := optimizeBA(Hk, Ad, B)
assert(tBA > buff)
for currentDebuff <= maxDebuff {
if currentDebuff%1e7 == 0 {
debug(fmt.Sprintf("%v", currentDebuff))
}
curesNeeded := 0
impossible := false
lastActionIsCure = false
healthBeforeBA := currentHealth
curePeriod := -1
firstCureI := -1
for i := 0; i < tBA-1; {
if curePeriod != -1 {
assert(curePeriod > 0)
assert(currentHealth == Hd-attack(Ak, currentDebuff, D))
attacksRemaining := tBA - 1 - i - 1
curesNeeded += attacksRemaining / curePeriod
break
}
healthAfterThis := currentHealth - attack(Ak, currentDebuff, D)
if healthAfterThis <= 0 {
if lastActionIsCure {
impossible = true
break
} else {
lastActionIsCure = true
if firstCureI == -1 {
firstCureI = i
} else if curePeriod == -1 {
curePeriod = i - firstCureI
}
curesNeeded++
currentHealth = Hd - attack(Ak, currentDebuff, D)
if currentHealth < 0 {
impossible = true
break
}
}
} else {
lastActionIsCure = false
currentHealth = healthAfterThis
i++
}
}
if impossible {
currentHealth = healthBeforeBA
if currentHealth-attack(Ak, currentDebuff+1, D) >= 0 {
currentT++
currentDebuff++
currentHealth = currentHealth - attack(Ak, currentDebuff, D)
continue
} else if Hd-attack(Ak, currentDebuff, D)-attack(Ak, currentDebuff+1, D) <= 0 {
break
} else {
currentT++
currentHealth = Hd - attack(Ak, currentDebuff, D)
currentDebuff++
currentT++
currentHealth -= attack(Ak, currentDebuff, D)
continue
}
}
thisTurnNumber := currentT + tBA + curesNeeded
if best > thisTurnNumber || best == -1 {
best = thisTurnNumber
}
currentHealth = healthBeforeBA
currentDebuff++
currentT++
if currentHealth-attack(Ak, currentDebuff, D) <= 0 {
currentT--
currentDebuff--
if Hd-attack(Ak, currentDebuff, D) <= 0 {
break
} else {
currentT++
currentHealth = Hd - attack(Ak, currentDebuff, D)
currentT++
currentDebuff++
currentHealth -= attack(Ak, currentDebuff, D)
if currentHealth <= 0 {
break
}
}
} else {
currentHealth -= attack(Ak, currentDebuff, D)
}
}
return best
}
func attack(Ak, currentDebuff, D int) int {
if currentDebuff*D >= Ak {
return 0
} else {
return Ak - currentDebuff*D
}
}
func optimizeBA(Hk, Ad, B int) (tBA, buff int) {
if B == 0 {
return int(math.Ceil(float64(Hk) / float64(Ad))), 0
}
b := sort.Search(Hk/B+1, func(b int) bool {
thisB := b + int(math.Ceil(float64(Hk)/float64(Ad+B*b)))
nextB := b + 1 + int(math.Ceil(float64(Hk)/float64(Ad+B*(b+1))))
return nextB >= thisB
})
return b + int(math.Ceil(float64(Hk)/float64(Ad+B*b))), b
}
Sample test cases given in question
4
11 5 16 5 0 0
3 1 3 2 2 0
3 1 3 2 1 0
2 1 5 1 1 1
Other files
2
65 7 19 41 1 27
36 41 85 76 28 49
Case #1: 4
Case #2: 5
1
3 1 3 1 1 1