CodeForces 518E Arthur and Questions(贪心 + 思维)题解
题意:给你a1~an,k,要求a1 + ... + ak < a2 + .... + ak+1 < a3 + ... + ak+2 <...,然后这里的ai有可能是?,要求你填?的数字,并且使a1~an的绝对值之和最小,不可能输出Incorrect sequence
思路:由上式要求我们可以得到a1 < ak+1 < ak+k+1 < ....且a2 < ak+2 < ak+k+2 < ....且...,所以可以转化为这样的要求。但是要绝对值最小怎么办,我们每次找连续的一连串?,尽可能让中间的位置为0,这样绝对值最小。所以我们先按中间赋值0这样去操作,然后再根据左右边界对整个区间进行修正,全加或全减一个数使得符合要求。
代码:
#include<cmath> #include<set> #include<queue> #include<cstdio> #include<vector> #include<cstring> #include <iostream> #include<algorithm> #include<bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxn = 1e5 + 10; const ull seed = 131; const int INF = 0x3f3f3f3f; const int MOD = 1000000009; int n, k, none[maxn]; ll a[maxn]; int id(int j, int k, int i){return j * k + i;} void solve(int ii, int l, int r){ int m = (l + r) / 2; int num = 0; for(int i = m; i <= r; i++) a[id(i, k, ii)] = num++; num = 0; for(int i = m; i >= l; i--) a[id(i, k, ii)] = num--; int dis; if(l != 0){ dis = a[id(l - 1, k, ii)] - a[id(l, k, ii)]; if(dis >= 0){ dis++; for(int i = l; i <= r; i++) a[id(i, k, ii)] += dis; } } if(id(r + 1, k, ii) <= n){ dis = a[id(r, k, ii)] - a[id(r + 1, k, ii)]; if(dis >= 0){ dis++; for(int i = l; i <= r; i++) a[id(i, k, ii)] -= dis; } } } int main(){ char o[20]; scanf("%d%d", &n, &k); for(int i = 1; i <= n; i++){ scanf("%s", o); if(o[0] == '?'){ none[i] = 1; } else{ sscanf(o, "%lld", &a[i]); } } for(int i = 1; i <= k; i++){ int l = 0, r = 0, ok = 0; for(int j = 0; j * k + i <= n; j++){ if(none[id(j, k, i)] && (j == 0 || !none[id(j - 1, k, i)])){ l = j; ok = 1; } if(none[id(j, k, i)]){ r = j; } else{ if(ok){ solve(i, l, r); ok = 0; } } } if(ok) solve(i, l, r); } ll tot = 0, pre; for(int i = 1; i <= k; i++){ tot += a[i]; } pre = tot; for(int i = k + 1; i <= n; i++){ tot = tot - a[i - k] + a[i]; if(tot <= pre){ printf("Incorrect sequence\n"); return 0; } pre = tot; } for(int i = 1; i <= n; i++){ if(i != 1) printf(" "); printf("%d", a[i]); } printf("\n"); return 0; }