一、題目
給一個長度為n的序列和一個整數x,每次操作可以選擇序列中的一個元素,將其從序列中刪去,或者將其值加一。
問至少操作多少次,可以使操作后的序列(可以為空)中數字之和是x的倍數。
輸入描述:
第一行兩個用空格隔開的正整數n和x,含義如問題描述中所述。
第二行是n個用空格隔開的正整數A[
1
],A[
2
],…,A[n],表示序列中n個元素的值。
n ≤
1000
,x ≤
1000
,A ≤
1000
輸出描述:一行一個整數,表示使序列中數字之和是x的倍數所需要的最少操作數。
樣例輸入
1
:
1
3
4
樣例輸出:
1
解釋:直接將序列中唯一的元素刪去即可。
輸入樣例
2
:
3
5
1
3
3
輸出:
2
解釋:可能的一種操作為,刪去最后一個元素,再使第一個元素加一,得到的序列為
2
3
。
二、分析
該問題要求我們找到最少的操作次數,使得經過若干次刪除元素或加一操作后,序列的數字之和是給定整數x的倍數。操作包括刪除一個元素或給一個元素加一,每次操作算一次。我們的目標是找到一個策略,通過這兩種操作的組合,使得總和成為x的倍數,并且操作次數最少。
首先,我們需要理解問題的目標是讓總和 S 滿足 S ≡ 0 mod x。初始時,序列的總和為 sum。如果 sum 已經是x的倍數,那么不需要任何操作,直接返回0。否則,我們需要通過刪除元素或增加元素的值來調整總和,使其成為x的倍數。
刪除元素會減少總和,而加一則會增加總和。我們需要在這兩種操作之間找到平衡,使得總和調整到最近的x的倍數,并且操作次數最少。
可能的策略包括:
1. **計算當前總和對x的余數**:計算初始總和 sum 對x取余得到 r。如果 r == 0,直接返回0。否則,我們需要調整總和,使其增加或減少一定的量,使得新的總和對x取余為0。
2. **考慮加一操作**:假設我們不刪除任何元素,那么可以通過給某些元素加一來增加總和。需要增加的總和量為 (x - r) mod x。對于每個元素,我們可以計算將其增加到足夠次數所需的操作數,使得總和增加 (x - r)。這可能適用于當總和接近x的下一個倍數時。
3. **考慮刪除元素**:刪除元素會減少總和。對于每個元素,我們可以計算刪除它之后的新總和,并檢查是否滿足條件。此外,可能需要結合刪除多個元素的情況。
4. **嘗試所有可能的組合**:對于較小的n和x,可以嘗試所有可能的刪除和加一的組合,找到操作次數最少的方案。但這種方法在n較大時效率較低。
5. **動態規劃**:可以考慮動態規劃的方法,記錄達到某個余數所需的最小操作次數。例如,我們可以維護一個數組 dp,其中 dp[i] 表示達到余數i所需的最小操作次數。初始時,dp[sum % x] = 0。然后,對于每個元素,我們可以更新 dp 數組,考慮加一或刪除該元素后的效果。
在實現時,我們需要綜合考慮上述策略,并選擇最適合問題規模的方法。對于題目給定的約束條件(n ≤ 1000,x ≤ 1000,A ≤ 1000),動態規劃可能是一個可行的選擇。
以樣例輸入1為例:
輸入:
1 3
4
初始總和是4,4 mod 3 = 1。我們需要調整總和到3的倍數。可以選擇刪除唯一的元素,操作次數為1,或者給該元素加2次達到6(3的倍數),操作次數為2。因此,最少操作次數是1。
樣例輸入2:
輸入:
3 5
1 3 3
初始總和是7,7 mod 5 = 2。我們需要調整總和到5的倍數。可能的策略是刪除最后一個3(總和變為4),然后給第一個元素加1(總和變為5,操作次數2)。或者有其他組合,但最少操作次數是2。
在代碼實現中,我們需要遍歷所有可能的操作組合,并找到操作次數最少的方案。這可能需要嘗試所有可能的刪除元素的子集,并計算對應的加一操作次數,或者使用動態規劃來記錄最小操作次數。
三、代碼
說起來你們可能不信,這段代碼是軍哥給我的
n, x = map(int, input().split())
a = list(map(int, input().split()))sum_a = sum(a)
remainder = sum_a % xif remainder == 0:print(0)
else:dp = [float('inf')] * xdp[remainder] = 0for num in a:new_dp = dp.copy()for i in range(x):if dp[i] != float('inf'):# 刪除當前元素new_remainder = i - (num % x)if new_remainder < 0:new_remainder += xnew_dp[new_remainder] = min(new_dp[new_remainder], dp[i] + 1)# 不刪除當前元素new_remainder_add = (i + num) % xnew_dp[new_remainder_add] = min(new_dp[new_remainder_add], dp[i])dp = new_dpmin_operations = min(dp[0], len(a)) # 最壞情況下刪除所有元素print(min_operations)
這段代碼首先計算初始總和對x的余數。然后使用動態規劃的方法來記錄達到每個可能的余數所需的最小操作次數。對于每個元素,考慮兩種情況:刪除該元素或不刪除該元素,更新動態規劃數組。最后,取達到余數0所需的最小操作次數,或者刪除所有元素的操作次數(作為最壞情況)。