<|instruction|>
Solve the below problem. The solution should start with an abridged problem statement. Then key observations. Then full solution based on the observations. Then C++ and Python implementations with comments.

304. Mars Stomatology
Time limit per test: 0.5 second(s)
Memory limit: 65536 kilobytes
input: standard
output: standard



Martian girl Kate has a toothache. The martian anatomy is very specific. They all have N teeth, each situated on one of K gums. Kate should pay dentist Ai mars euros for the treatment of i-th tooth. Moreover, Kate should pay Bj euros for the anesthesia of the gum j if this gum has at least one tooth cured. What is the maximal number of teeth Kate can cure if parents gave her P mars euros?

Input
The first line of the input contains three integer numbers N, K and P (1≤ N≤ 600; 1≤ K≤ N; 1≤ P≤ 106). The second line contains the sequence of K integer numbers B1, B2,..., BK, where Bj is the cost of anesthesia of the j-th gum (1≤ Bj≤ 600 for all j = 1, 2,..., K). Each of the following N lines contains the description of tooth. Each description is the pair of integer numbers Ai and Ci, where Ai is the cost of curing of the i-th tooth, Ci is the number of the gum the tooth occupies (1≤ Ai≤ 600; 1≤ Ci≤ K for all i = 1, 2,..., N).

Output
Write to the first line of the output the maximal number of cured teeth S. Write to the second line S numbers of the cured teeth from the given set. If there are several solutions output any of them.

Example(s)
sample input
sample output
4 2 10
1 2
1 2
5 2
3 1
3 2
3
4 3 1

<|response|>
1. Abridged Problem Statement  
You have N teeth divided among K gums. Treating tooth i costs A[i] mars euros, and if you treat any tooth on gum j you must also pay a fixed anesthesia cost B[j] (once per gum). Given a total budget P, select a subset of teeth to maximize the number of treated teeth. Output that maximum count and any valid list of selected tooth indices.

2. Key Observations  
- This is a variant of the knapsack problem with “group‐fixed” costs: each gum is a group, picking ≥1 item in the group incurs a one-time cost B[j].  
- Within each gum, you always want to pick the cheapest teeth first.  
- We can define a DP over the gums: for the first g gums and a target of t treated teeth, store the minimum total cost.  
- After filling the DP table, scan for the largest t such that cost ≤ P. Then backtrack to recover which teeth were taken from each gum.

3. Full Solution Approach  
a. Grouping and sorting  
   • Build an array `gums[1…K]`, each containing the list of (A[i], original tooth index) for teeth i assigned to that gum.  
   • Sort each `gums[j]` by ascending A[i].  

b. DP state and initialization  
   • Let dp[g][t] = minimal cost to treat exactly t teeth using only the first g gums (g ranges 0…K, t ranges 0…N).  
   • Initialize dp[0][0] = 0, and dp[0][t>0] = ∞.  

c. Transitions  
   For each gum g from 1 to K, for each achievable t from 0 to N with finite dp[g−1][t], we have two choices:  
   1. Skip gum g entirely:  
        dp[g][t] = min(dp[g][t], dp[g−1][t])  
        record choice[g][t] = 0 (meaning “took 0 teeth from this gum”).  
   2. Take p ≥ 1 teeth from gum g, up to the number of teeth in that gum or up to remaining capacity N−t:  
        Let prefixSum[p] = sum of the p cheapest A-costs in gum g.  
        New cost = dp[g−1][t] + B[g] + prefixSum[p].  
        dp[g][t+p] = min(dp[g][t+p], new cost), record choice[g][t+p] = p.  

d. Finding the answer  
   • After processing all K gums, scan t = N down to 0. The largest t with dp[K][t] ≤ P is the maximum number of treatable teeth.  

e. Reconstructing the chosen teeth  
   • Starting from (g = K, t = best_t), look at choice[g][t]: if it is p>0, you took the p cheapest teeth from gum g, so record their original indices. Then set t ← t−p and g ← g−1. If choice[g][t] = 0, just g ← g−1.  
   • At the end, you have all chosen indices; sort them if you like and print.

Time complexity is O(N² + N log N): grouping/sorting is O(N log N), DP is O(K·N·max_group_size) ≤ O(N²).

4. C++ Implementation with Detailed Comments  
#include <bits/stdc++.h>
using namespace std;

// dp[g][t].first  = minimum cost to treat t teeth from first g gums
// dp[g][t].second = how many teeth taken from gum g in this optimal transition
static const int INF = 1e9;

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int N, K, P;
    cin >> N >> K >> P;

    vector<int> B(K+1);
    for(int j = 1; j <= K; j++){
        cin >> B[j];
    }

    // Group teeth by gum, store (cost, original_index)
    vector<vector<pair<int,int>>> gums(K+1);
    for(int i = 1; i <= N; i++){
        int a, c;
        cin >> a >> c;
        gums[c].push_back({a, i});
    }

    // Sort each gum's teeth by ascending treatment cost
    for(int j = 1; j <= K; j++){
        sort(gums[j].begin(), gums[j].end());
    }

    // Prepare prefix sums for each gum to get sum of p cheapest quickly
    vector<vector<int>> prefix(K+1);
    for(int j = 1; j <= K; j++){
        int sz = gums[j].size();
        prefix[j].assign(sz+1, 0);
        for(int i = 0; i < sz; i++){
            prefix[j][i+1] = prefix[j][i] + gums[j][i].first;
        }
    }

    // DP table and choice recorder
    vector<vector<pair<int,int>>> dp(K+1, vector<pair<int,int>>(N+1, {INF, 0}));
    dp[0][0] = {0, 0};

    // Main DP loop over gums
    for(int g = 1; g <= K; g++){
        int sz = gums[g].size();
        for(int t = 0; t <= N; t++){
            if(dp[g-1][t].first == INF) continue;
            int baseCost = dp[g-1][t].first;

            // Option 1: take 0 teeth from gum g
            if(baseCost < dp[g][t].first){
                dp[g][t] = {baseCost, 0};
            }

            // Option 2: take p = 1..sz teeth
            for(int p = 1; p <= sz && t + p <= N; p++){
                int costWithThis = baseCost + B[g] + prefix[g][p];
                if(costWithThis < dp[g][t + p].first){
                    dp[g][t + p] = {costWithThis, p};
                }
            }
        }
    }

    // Find maximum number of teeth treatable within budget P
    int best = 0;
    for(int t = 0; t <= N; t++){
        if(dp[K][t].first <= P){
            best = t;
        }
    }
    cout << best << "\n";

    // Reconstruct which teeth were chosen
    vector<int> answer;
    int t = best;
    for(int g = K; g >= 1; g--){
        int p = dp[g][t].second;
        if(p > 0){
            // take the p cheapest teeth from gum g
            for(int i = 0; i < p; i++){
                answer.push_back(gums[g][i].second);
            }
            t -= p;
        }
        // if p==0, we skipped this gum
    }

    sort(answer.begin(), answer.end());
    for(int idx: answer){
        cout << idx << " ";
    }
    cout << "\n";
    return 0;
}

5. Python Implementation with Detailed Comments  
import sys
input = sys.stdin.readline

def main():
    N, K, P = map(int, input().split())
    B = [0] + list(map(int, input().split()))

    # Group teeth by gum: gums[j] = list of (cost, original_index)
    gums = [[] for _ in range(K+1)]
    for idx in range(1, N+1):
        a, c = map(int, input().split())
        gums[c].append((a, idx))

    # Sort each gum's teeth by ascending cost
    for j in range(1, K+1):
        gums[j].sort()

    # Build prefix sums: prefix[j][p] = sum of p cheapest costs in gum j
    prefix = [[0] for _ in range(K+1)]
    for j in range(1, K+1):
        for cost, _ in gums[j]:
            prefix[j].append(prefix[j][-1] + cost)

    INF = 10**15
    # dp[g][t] = (min_cost, how_many_taken_from_gum_g)
    dp = [ [ (INF, 0) for _ in range(N+1) ] for _ in range(K+1) ]
    dp[0][0] = (0, 0)

    # DP over gums
    for g in range(1, K+1):
        sz = len(gums[g])
        for t in range(N+1):
            prev_cost, _ = dp[g-1][t]
            if prev_cost >= INF:
                continue
            # Option 1: skip gum g
            if prev_cost < dp[g][t][0]:
                dp[g][t] = (prev_cost, 0)
            # Option 2: take p teeth (1..sz)
            for p in range(1, sz+1):
                if t + p > N:
                    break
                cost2 = prev_cost + B[g] + prefix[g][p]
                if cost2 < dp[g][t+p][0]:
                    dp[g][t+p] = (cost2, p)

    # Find the best t within budget
    best = max(t for t in range(N+1) if dp[K][t][0] <= P)
    print(best)

    # Reconstruct chosen teeth
    res = []
    t = best
    for g in range(K, 0, -1):
        _, taken = dp[g][t]
        if taken > 0:
            # pick the 'taken' cheapest teeth from gum g
            for i in range(taken):
                res.append(gums[g][i][1])
            t -= taken

    res.sort()
    print(*res)

if __name__ == "__main__":
    main()