I、Identical Day from 第二屆“聯想杯”
阿新 • • 發佈:2021-06-16
貪心的策略有些問題,如果用堆維護最長段對半分顯然不會是最優的(儘量均分成3段比中間切一刀加上左1/4切一刀更優)
正確的貪心策略是堆維護把一段均分成x段的變成均分成x+1段可以減少多少權值,每次取最大肯定是最優的。
#include<bits/stdc++.h> using namespace std; #define ll long long #define fastio ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL) #define pii pair<int,int> #define pll pair<ll,ll> const double PI = acos(-1); const int inf = 1e9 + 7; const ll lnf = 1e18 + 7; const int maxn = 2e5 + 5; ll mod = 1e9 + 7; //不應該去貪心對半分,而是去貪心每次取可消除差值最大 ll f(ll x) { return x * (x + 1) / 2; } ll cut(ll x, ll n)//把x長的1分成n+1份 { if (n == x) return 0; x -= n;//中間要切n刀,分成n+1份,每份長x/(n+1) n++; if (x % n == 0)//剛好均分 return n * f(x / n); ll cha = x % n; return cha * f(x / n + 1) + (n - cha) * f(x / n); } struct node { ll a, b, c; friend bool operator<(node x, node y) { return x.a < y.a; } }; priority_queue<node>q; int main() { fastio; ll n, k; cin >> n >> k; string s; cin >> s; ll sum = 0; ll now = 0; for (int i = 0; i < s.length(); i++) { if (s[i] == '0') { if (sum) { now += f(sum); q.push({ f(sum) - cut(sum,1),1,sum }), sum = 0; } } else sum++; } if (sum) { now += f(sum); q.push({ f(sum) - cut(sum,1),1,sum }), sum = 0; } ll ans = 0; while (now > k && !q.empty()) { ll cha = q.top().a; n = q.top().b, sum = q.top().c; q.pop(); //cout << cha << endl; ans++; now -= cha; if (n < sum) q.push({ cut(sum, n) - cut(sum, n + 1), n + 1,sum }); } cout << ans; return 0; }