дан массив. Можно за одну операцию удалить элемент...

創建於:2026年6月26日

使用 GPT-5.5 Thinking 回答 Chat01

問題

дан массив. Можно за одну операцию удалить элемент если сумма соседей которые у него есть четная найди минимальную длину массива полученного путем операций

Python

python
from functools import lru_cache def minlen(s, single_deletable=False): s=tuple(s) @lru_cache(None) def f(t): m=len(t) best=m for i in range(m): neigh=[] if i>0: neigh.append(t[i-1]) if i<m-1: neigh.append(t[i+1]) if not neigh: ok = single_deletable # sum 0 even else: ok=(sum(neigh)%2==0) if ok: best=min(best, f(t[:i]+t[i+1:])) return best return f(s) for single in [False, True]: print("single",single) for n in range(1,8): vals={} for x in range(1<<n): s=tuple((x>>i)&1 for i in range(n)) vals[s]=minlen(s,single) print(n, sorted(set(vals.values())), {''.join(map(str,k)):v for k,v in vals.items() if v==max(vals.values())}) print()

Python

python
from functools import lru_cache def terminal_lengths(s, single=False): s=tuple(s) @lru_cache(None) def rec(t): m=len(t) nexts=[] for i in range(m): neigh=[] if i>0: neigh.append(t[i-1]) if i<m-1: neigh.append(t[i+1]) ok = (sum(neigh)%2==0) if neigh else single if ok: nexts.append(t[:i]+t[i+1:]) if not nexts: return {m} out=set() for u in nexts: out |= rec(u) return out return rec(s) for n in range(1,8): non=[] for x in range(1<<n): s=tuple((x>>i)&1 for i in range(n)) tl=terminal_lengths(s,False) if len(tl)>1: non.append((''.join(map(str,s)),tl)) break print(n, non[:1])

Python

python
def genA(b, maxn): A={""} if maxn>=1: A.add(str(1-b)) changed=True while changed: changed=False for x in list(A): for y in list(A): s=x+str(b)+y if len(s)<=maxn and s not in A: A.add(s); changed=True return A for b in [0,1]: A=genA(b,5) print("A",b) for n in range(6): alln={format(x,f'0{n}b') for x in range(1<<n)} miss=sorted(alln-A) print(n, len(alln)-len(miss), "miss", miss[:10])

Python

python
for b in [0,1]: A=genA(b,4) print(b, sorted([s for s in A if len(s)==4]))

Python

python
def genP0(maxn): A0=genA(0,maxn) P={""} if maxn>=1: P.add("1") changed=True while changed: changed=False for x in list(P): for y in A0: s=x+"0"+y if len(s)<=maxn and s not in P: P.add(s); changed=True return P P=genP0(5) for n in range(6): alln={format(x,f'0{n}b') for x in range(1<<n)} print(n, sorted(alln-P)[:20], "accepted", sorted([s for s in P if len(s)==n])[:20])

Python

python
from collections import deque INF=10**9 def minlen_fast(bits): n=len(bits) if n==0: return 0 b=[None]+list(bits) # prefix no 11 for before i pref_no11=[True]*(n+1) # pref_no11[k] for [1..k] for k in range(1,n+1): pref_no11[k]=pref_no11[k-1] and not (k>=2 and b[k-1]==1 and b[k]==1) # suffix no 11 for [i..n] suff_no11=[True]*(n+2) for k in range(n,0,-1): suff_no11[k]=suff_no11[k+1] and not (k<n and b[k]==1 and b[k+1]==1) dp=[INF]*(n+1) # deques for parity candidates (index, dp) dq=[deque(), deque()] # Need add previous indices before processing j. For j=1 no prev. last11=0 # max start <= j-2? last00=0 for j in range(1,n+1): if j>1: i=j-1 # add dp[i] to parity deque p=b[i] while dq[p] and dq[p][-1][1] >= dp[i]: dq[p].pop() dq[p].append((i,dp[i])) # update last bad starts up to j-2 incrementally # At j, include pair start j-2? if j>=3: k=j-2 if b[k]==1 and b[k+1]==1: last11=k if b[k]==0 and b[k+1]==0: last00=k # pop outdated for target b[j] if b[j]==0: L=last11 else: L=last00 p=b[j] while dq[p] and dq[p][0][0] < L: dq[p].popleft() # source if b[j]==0 and pref_no11[j-1]: dp[j]=1 if b[j]==1 and j==1: dp[j]=1 # adjacent any previous j-1 if j>1: dp[j]=min(dp[j], dp[j-1]+1) # same parity long edge if dq[p]: dp[j]=min(dp[j], dq[p][0][1]+1) ans=INF for i in range(1,n+1): if b[i]==0 and suff_no11[i+1]: ans=min(ans, dp[i]) if b[i]==1 and i==n: ans=min(ans, dp[i]) return ans for n in range(1,10): ok=True bad=None for x in range(1<<n): bits=tuple((x>>(n-1-i))&1 for i in range(n)) # normal a=minlen(bits,False) c=minlen_fast(bits) if a!=c: ok=False; bad=(bits,a,c); break print(n, ok, bad)

思考

Adjusting for full-deletion and edge cases

I’m thinking that if I allow single deletion, the answer might sometimes be 0, but in other cases, it stays the same. I’ll need to adjust quickly if the full deletion is allowed. The condition for full deletion seems to depend on neighbors, and I need to refine this further.

Thought for 2m 31s

回答

Нужна работать только с чётностью элементов.

Пусть:

text
0 — чётный элемент 1 — нечётный элемент

Элемент можно удалить:

text
внутри массива: если левый и правый сосед одной чётности на краю массива: если единственный сосед чётный

Жадно удалять нельзя. Например:

text
1 0 1

Если удалить 0, останется 1 1, дальше нельзя.
Но можно удалить крайние 1, и останется 0.

Ниже решение за O(n).

cpp
#include <bits/stdc++.h> using namespace std; int minimalLength(vector<long long>& a) { int n = a.size(); vector<int> b(n + 1); for (int i = 1; i <= n; i++) { b[i] = abs(a[i - 1]) % 2; // 0 - even, 1 - odd } /* prefNo11[i] = true, если на отрезке [1..i] нет двух соседних нечётных элементов. */ vector<int> prefNo11(n + 1, 1), suffNo11(n + 2, 1); for (int i = 1; i <= n; i++) { prefNo11[i] = prefNo11[i - 1]; if (i >= 2 && b[i - 1] == 1 && b[i] == 1) { prefNo11[i] = 0; } } for (int i = n; i >= 1; i--) { suffNo11[i] = suffNo11[i + 1]; if (i < n && b[i] == 1 && b[i + 1] == 1) { suffNo11[i] = 0; } } const int INF = 1e9; /* dp[i] = минимальное количество оставленных элементов, если последним оставленным сейчас является i. */ vector<int> dp(n + 1, INF); deque<pair<int, int>> q[2]; // q[0] — кандидаты с чётным последним элементом // q[1] — кандидаты с нечётным последним элементом int last11 = 0; int last00 = 0; for (int j = 1; j <= n; j++) { if (j > 1 && dp[j - 1] < INF) { int p = b[j - 1]; while (!q[p].empty() && q[p].back().second >= dp[j - 1]) { q[p].pop_back(); } q[p].push_back({j - 1, dp[j - 1]}); } if (j >= 3) { int k = j - 2; if (b[k] == 1 && b[k + 1] == 1) { last11 = k; } if (b[k] == 0 && b[k + 1] == 0) { last00 = k; } } int p = b[j]; int L; if (p == 0) { L = last11; } else { L = last00; } while (!q[p].empty() && q[p].front().first < L) { q[p].pop_front(); } // j — первый оставленный элемент if (b[j] == 0 && prefNo11[j - 1]) { dp[j] = 1; } if (b[j] == 1 && j == 1) { dp[j] = 1; } // предыдущий оставленный элемент стоит прямо перед j if (j > 1 && dp[j - 1] < INF) { dp[j] = min(dp[j], dp[j - 1] + 1); } // предыдущий оставленный элемент той же чётности if (!q[p].empty()) { dp[j] = min(dp[j], q[p].front().second + 1); } } int ans = INF; for (int i = 1; i <= n; i++) { // если последний оставленный элемент чётный, // хвост после него можно удалить, если там нет 11 if (b[i] == 0 && suffNo11[i + 1]) { ans = min(ans, dp[i]); } // если последний оставленный элемент нечётный, // он должен быть последним в исходном массиве if (b[i] == 1 && i == n) { ans = min(ans, dp[i]); } } return ans; } int main() { int n; cin >> n; vector<long long> a(n); for (int i = 0; i < n; i++) { cin >> a[i]; } cout << minimalLength(a) << '\n'; return 0; }

Если по условию один последний элемент тоже можно удалить, потому что сумма его соседей равна 0, тогда перед return ans; нужно добавить проверку:

cpp
if (prefNo11[n]) { ans = 0; }

То есть если в массиве нет двух соседних нечётных элементов, его можно удалить полностью.

分享這個問答