```go
package main
import (
"fmt"
"sort"
)
func main() {
var n, k int
fmt.Scan(&n, &k)
prices := make([]int, n)
types := make([]int, n)
for i := 0; i < n; i++ {
fmt.Scan(&prices[i], &types[i])
}
// indices sorted by price descending
indices := make([]int, n)
for i := 0; i < n; i++ {
indices[i] = i
}
sort.Slice(indices, func(a, b int) bool {
return prices[indices[a]] > prices[indices[b]]
})
// Separate stools and pencils in sorted order (descending price)
var stools []int
var pencils []int
for _, idx := range indices {
if types[idx] == 1 {
stools = append(stools, idx)
} else {
pencils = append(pencils, idx)
}
}
// Strategy: We have k carts. We want to maximize discounts.
// Each cart with at least one stool gets 50% off the cheapest item in that cart.
// To maximize total discount, we want to maximize the sum of the cheapest items in carts that contain stools.
//
// Key insight: Sort all items by price descending. We can create up to min(k, len(stools)) carts with stools.
// For each such cart, the discount applies to the cheapest item. To maximize the discount on expensive items,
// we want each stool-cart to have its cheapest item be as expensive as possible.
//
// Greedy approach: sort items descending. Assign items to carts greedily.
// We can have at most min(k, len(stools)) carts with discounts.
// For each discount cart, we want exactly one stool and possibly one pencil (or just the stool).
// Actually, we want the minimum item in the cart to be as large as possible.
//
// Better approach: We have stools sorted desc and pencils sorted desc.
// We can form up to min(k, len(stools)) "discount groups". Each discount group has one stool.
// To maximize the cheapest item in each group, pair the most expensive pencils with stools of similar or higher price.
// Actually, pair each stool with at most one pencil, and the discount is on the min of the two.
// If we have s stools and p pencils, and k carts:
// - We must use exactly k carts, none empty.
// - If s >= k: put at least one stool per cart. Extra stools go into existing carts.
// Each cart has a stool so discount on cheapest. Put all pencils into the cart with the most expensive stool
// (or distribute to maximize discounts). Actually if all carts have stools, discount is on cheapest item per cart.
// We want to maximize sum of min-items. Put pencils into carts where they won't reduce the min too much.
// Best: put all pencils into one cart (the one with the cheapest stool won't matter much).
// Actually we want pencils in carts where the stool is cheaper than the pencil, so pencil doesn't reduce min.
// This is complex. Let me think about it differently with a known greedy:
// Sort all items descending. Form groups: first k items each go into separate carts (one item each).
// Remaining items go into the last cart (cart k). But we need to optimize discounts.
// Actually, a cleaner known approach for this problem:
// Sort all items descending by price. Take groups of items. The first k-1 groups have size 1 or 2,
// and the last group has the rest. In each group that contains a stool, the cheapest item gets 50% off.
// We want to maximize total discount = sum of cheapest items in groups with stools / 2.
// Let me try: merge stools and pencils sorted descending. Greedily form k groups from the top.
// Each group: if next item is a stool, take it alone (discount = price/2). Or pair it with next pencil if beneficial.
// If next is pencil, take it alone (no discount) or pair with a stool.
// This needs DP. Let me use DP.
// dp[i][j] = max discount using first i stools and j pencils to fill some carts.
// Actually, let me just try all possible groupings via DP on sorted items.
// Simpler: sort all items desc. We need to partition into k non-empty groups (consecutive in sorted order).
// The discount per group = cheapest_item/2 if group contains a stool, else 0.
// We want to maximize total discount. The cheapest item in a consecutive group is the last one.
// dp[i][j] = max discount partitioning first i items into j groups
// This is O(n^2 * k) which is fine for n,k <= 1000.
allItems := make([]int, n)
copy(allItems, indices)
// allItems is sorted descending by price
hasStool := make([][]bool, n+1)
for i := 0; i <= n; i++ {
hasStool[i] = make([]bool, n+1)
}
// hasStool[l][r] = true if items allItems[l..r-1] contain a stool
// Precompute prefix count of stools
stoolPrefix := make([]int, n+1)
for i := 0; i < n; i++ {
stoolPrefix[i+1] = stoolPrefix[i]
if types[allItems[i]] == 1 {
stoolPrefix[i+1]++
}
}
stoolInRange := func(l, r int) bool { // [l, r)
return stoolPrefix[r]-stoolPrefix[l] > 0
}
// dp[i][j] = max total discount when first i items (sorted desc) are split into j non-empty consecutive groups
// Transition: dp[i][j] = max over l in [j-1, i-1] of dp[l][j-1] + discount(l, i)
// discount(l, i) = prices[allItems[i-1]]/2 if stoolInRange(l, i), else 0
// (because items are sorted desc, cheapest in group [l..i-1] is allItems[i-1])
const NEG_INF = int64(-1e18)
dp := make([][]int64, n+1)
parent := make([][]int, n+1) // for reconstruction
for i := 0; i <= n; i++ {
dp[i] = make([]int64, k+1)
parent[i] = make([]int, k+1)
for j := 0; j <= k; j++ {
dp[i][j] = NEG_INF
parent[i][j] = -1
}
}
dp[0][0] = 0
for j := 1; j <= k; j++ {
for i := j; i <= n; i++ {
for l := j - 1; l < i; l++ {
if dp[l][j-1] == NEG_INF {
continue
}
discount := int64(0)
if stoolInRange(l, i) {
discount = int64(prices[allItems[i-1]])
}
val := dp[l][j-1] + discount
if val > dp[i][j] {
dp[i][j] = val
parent[i][j] = l
}
}
}
}
// Reconstruct groups
groups := make([][]int, k)
pos := n
for j := k; j >= 1; j-- {
l := parent[pos][j]
group := []int{}
for idx := l; idx < pos; idx++ {
group = append(group, allItems[idx])
}
groups[j-1] = group
pos = l
}
// Compute total price
totalPrice := int64(0)
for i := 0; i < n; i++ {
totalPrice += int64(prices[i]) * 2
}
// discount is dp[n][k], which is sum of cheapest items in groups with stools
// actual saving = dp[n][k] / 2 (in terms of original prices)
// Let's compute in halves to avoid floating point
// total in half-units = sum(prices)*2, discount = dp[n][k]
totalHalf := totalPrice - dp[n][k]
fmt.Printf("%d.%d\n", totalHalf/2, (totalHalf%2)*5)
for i := 0; i < k; i++ {
fmt.Print(len(groups[i]))
for _, idx := range groups[i] {
fmt.Printf(" %d", idx+1)
}
fmt.Println()
}
}
```