import java.io.*; import java.util.*; public clas...
Создано: 5 июля 2025 г.
Отвечено с использованием O4 Mini High от Chat01
Создано: 5 июля 2025 г.
Отвечено с использованием O4 Mini High от Chat01
import java.io.;
import java.util.;
public class Main {
static int n, m;
static long total; // sum of f(a) over all sequences
textpublic static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int T = Integer.parseInt(br.readLine().trim()); StringBuilder sb = new StringBuilder(); while (T-- > 0) { StringTokenizer st = new StringTokenizer(br.readLine()); n = Integer.parseInt(st.nextToken()); m = Integer.parseInt(st.nextToken()); total = 0; // a[1..n], 1-based for convenience int[] a = new int[n+1]; genSequence(1, a); sb.append(total % m).append('\n'); } System.out.print(sb); } // Recursively build a[1..n] static void genSequence(int i, int[] a) { if (i > n) { // we have a full valid sequence; compute f(a) List<Integer> tokens = new ArrayList<>(); for (int t = 1; t <= n; t++) tokens.add(t); long fa = countRemovals(1, a, tokens); total = (total + fa) % m; return; } // choose a[i] in [0..i] for (int v = 0; v <= i; v++) { a[i] = v; genSequence(i+1, a); } } // Recursively count removal ways for sequence a, starting at step i, // with 'tokens' currently still present. static long countRemovals(int i, int[] a, List<Integer> tokens) { if (i > n) { // performed all removals return 1; } if (a[i] == 0) { // no removal this step return countRemovals(i+1, a, tokens); } long ways = 0; // collect all eligible token positions t in [a[i]..i] for (int idx = 0; idx < tokens.size(); idx++) { int t = tokens.get(idx); if (t >= a[i] && t <= i) { // remove t tokens.remove(idx); ways = (ways + countRemovals(i+1, a, tokens)) % m; // backtrack tokens.add(idx, t); } } return ways; }
}
optimize this
python# Let's brute compute total for small n without mod m (m large). from functools import lru_cache def compute_total(n): # compute total sum f(a) over sequences total = 0 # generate all sequences a[1..n] with a[i] in 0..i # recursion def gen(i, a): nonlocal total if i > n: # compute f(a) # tokens from 1..n # count removals total += count(1, tuple(a)) return for v in range(i+1): # 0..i a.append(v) gen(i+1, a) a.pop() @lru_cache(None) def count(i, a, tokens=None): # tokens represented as tuple if tokens is None: tokens = tuple(range(1, n+1)) if i > n: return 1 ai = a[i-1] if ai == 0: return count(i+1, a, tokens) ways = 0 # for each eligible token new_tokens = list(tokens) for idx, t in enumerate(tokens): if ai <= t <= i: # remove t nt = list(tokens) nt.pop(idx) ways += count(i+1, a, tuple(nt)) return ways gen(1, []) return total for n in range(1,7): print(n, compute_total(n))
Here’s a purely recursive solution that collapses the two‐pass approach (first over all a, then over all removal orders) into one, and which avoids all of the costly List creations and index‐shifts:
javaimport java.io.*; import java.util.*; public class Main { static int n, m; static long total; // tokens[k] = the k-th token still present; we keep tokenCount of them static int[] tokens; public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int T = Integer.parseInt(br.readLine().trim()); StringBuilder sb = new StringBuilder(); while (T-- > 0) { StringTokenizer st = new StringTokenizer(br.readLine()); n = Integer.parseInt(st.nextToken()); m = Integer.parseInt(st.nextToken()); // initialize total = 0; tokens = new int[n]; for (int i = 0; i < n; i++) tokens[i] = i + 1; // start at step 1, with product = 1 and all n tokens present dfs(1, 1L, n); sb.append(total).append('\n'); } System.out.print(sb); } /** * @param step current removal step (1..n) * @param prod product of all previously chosen t's (i.e. number of choices * for a[?] so far), mod m * @param tokenCount how many tokens remain in tokens[0..tokenCount-1] */ static void dfs(int step, long prod, int tokenCount) { if (step > n) { // we've processed all steps → accumulate one full (a+removal) count total = (total + prod) % m; return; } // 1) choose a[step] = 0 (no removal this step) dfs(step + 1, prod, tokenCount); // 2) removal: pick any token ≤ step // and for each t we also have t different a[step]-values (1..t) for (int j = 0; j < tokenCount; j++) { int t = tokens[j]; if (t <= step) { // remove tokens[j] by swapping it out of the active prefix tokens[j] = tokens[tokenCount - 1]; dfs(step + 1, (prod * t) % m, tokenCount - 1); // restore tokens[j] = t; } } } }
Single recursive pass
Instead of first iterating all sequences a[1..n] and then, for each, recursing again over removal-orders, we do both at once. At step i we either:
a[i]=0 case), ort and account for the fact there are t possible lower‐bounds a[i]=1..t by multiplying our running product by t.This removes an entire factor of n in the branching and cuts out the inner list recursion altogether.
Primitive arrays + in-place swaps
int[] tokens and an integer tokenCount.tokenCount, then swap it back on return.new ArrayList, no remove(idx) (which is O(n)), and no boxing/unboxing of Integer.Early modulo
We do (prod * t) % m on each step, and %m on every addition to total, so we never let our intermediate values overflow or blow up.
With these changes you’ve eliminated all of the list‐copying and double‐recursion overhead and pushed the constant factor down dramatically.