HDU 6237 A Simple Stone Game——思維
阿新 • • 發佈:2018-11-16
題意:有n(1e5)堆石子,第i堆石子有a[i](1e5)個,現在可以進行任意次操作,每次操作可以把一個石頭從一堆挪到另一堆,問最少操作幾次可以達成這個條件:存在一個x,使得每堆的石子數量都是x的倍數
思路:首先對石子總數進行質因分解,x一定是這些素因子中的一個,這個是我憑感覺蒙的,事實證明確實是對的。然後列舉素因子x,算每個素因子對應的最小移動次數,我們設b[i]=a[i]%x,那麼我們對b從小到達排序,可以這麼理解,為了實現移動次數最少,我們應該把值小的那些b移走,補充值大的那些b,進一步我們應該將值最小的b補充給值最大的b,這個記錄一個l,r,模擬一下就可以了,要注意的是因為x是素因子,所以移動一定是合法的,這樣每個素因子x對應的最小移動次數我們就算完了,最後在這些值中取一個最小值就可以
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e5 + 10; const ll INF = 1e14; int T, N; ll a[maxn], p[maxn], b[maxn]; int main() { scanf("%d", &T); while (T--) { scanf("%d", &N); ll sum = 0; for (int i = 1; i <= N; i++) scanf("%lld", &a[i]), sum += a[i]; int cnt = 0; for (ll i = 2; i * i <= sum; i++) { if (sum % i == 0) { p[++cnt] = i; while (sum % i == 0) sum /= i; } } if (sum > 1) p[++cnt] = sum; ll ans = INF; for (int i = 1; i <= cnt; i++) { for (int j = 1; j <= N; j++) { b[j] = a[j] % p[i]; } sort(b+1, b+1+N); int l = 1, r = N; ll res = 0; while (l < r) { if (b[l] == 0) { l++; continue; } res += b[l]; while (b[l] != 0) { if (b[r] + b[l] < p[i]) { b[r] += b[l]; b[l] = 0; } else { b[l] -= p[i] - b[r]; b[r--] = p[i]; } } l++; } ans = min(ans, res); } printf("%lld\n", ans); } return 0; }