给定一长度为\(n\)的序列\(s\),定义其健美值为:$$\sum\limits_{i=1}^{n}|s_i - i|$$由于 zzq 喜欢健美,因此 zzq 但愿减少\(s\)的健美值,以陪衬 zzq 的健美。为了达到 zzq 的目的,zzq 但愿你对序列进行旋转操做,一次旋转操做可使序列中的全部元素前移一位,并使\(s_1\)移动到\(s_n\)。
能够进行任意次旋转操做,zzq 但愿旋转后的健美值最小,请找出这个最小值。spa
智商检测题
咱们发现对于每一个数,移动每一次会使本来差小于0的数减小1的贡献,使原先差大于0的增长1的贡献。因此记录大于0的数以及小于0的数的个数,同时维护一个桶记录某一个差值有几个数,用于计算小于0变成大于0时的状况。枚举移动的距离,直接计算便可。code
int main() { poread(n); for (register int i = 1; i <= n; ++i) poread(a[i]); for (register int i = 1; i <= n; ++i) { register int x = a[i] - i; x >= 0 ? (++cnt1, sum += x) : (++cnt2, sum += -x, ++b[-x]); } for (register int i = 1; i < n; ++i) { register int x = a[i] - 1, y = a[i] - n; --cnt1, sum -= x; ++cnt2, sum += -y, ++b[-y + i]; sum += cnt1 - cnt2 + 1; if (b[i]) cnt1 += b[i], cnt2 -= b[i]; ans = min(ans, sum); } cout << ans << endl; }
zzq 是一个善于思考的好学生。
因而 zzq 想往他的背包中放序列。
某一天 zzq 获得了一个长度为\(n\)的序列\(\{a_i\}\)。而后 zzq 说,若是对于一段区间\([L,R]\),存在\(L \leq k \leq R\)使得\(\forall i \in [L,R]\)都有\(a_k | a_i\),咱们认为它有价值,价值为\(R - L\)(若不知足条件则没有价值)。
如今 zzq 想知道全部区间中价值最大为多少,最大价值的区间有多少个,以及这些区间分别是什么。it
ST表维护区间gcd以及区间最小值,二分长度,若是该区间最小值等于区间gcd这个区间就是合法的。
复杂度\(O(n \log^2 n)\)class
inline int gcd(int a,int b) { while(b ^= a ^= b ^= a %= b); return a; } const int MAXN = 5e5 + 10; int ST[MAXN][20]; int TS[MAXN][20]; int a[MAXN]; int n; int ans[MAXN], tot; inline int query(const int &l, const int &r) { register int k = log2(r - l + 1); return gcd(ST[l][k], ST[r - (1 << k) + 1][k]); } inline int yreuq(const int &l, const int &r) { register int k = log2(r - l + 1); return min(TS[l][k], TS[r - (1 << k) + 1][k]); } inline bool check(const int &mid) { for(register int l = 1, r = l + mid - 1; r <= n; ++l,++r) { if(query(l, r) == yreuq(l, r)) return true; } return false; } signed main() { poread(n); for(register int i = 1; i <= n; ++i) poread(a[i]); for(register int i = 1; i <= n; ++i) ST[i][0] = a[i]; int t = log2(n) + 1; for(register int j = 1; j <= t; ++j) for(register int i = 1; i<= n - (1 << j) + 1; ++i) ST[i][j] = gcd(ST[i][j - 1], ST[i + (1 << (j - 1))][j - 1]); for(register int i = 1; i <= n; ++i) TS[i][0] = a[i]; for(register int j = 1; j <= t; ++j) for(register int i = 1; i <= n - (1 << j) + 1; ++i) TS[i][j] = min(TS[i][j - 1], TS[i + (1 << (j - 1))][j - 1]); register int l = 2, r = n, mid, res; while(l <= r) { mid = (l + r) >> 1; if(check(mid)) res = mid, l = mid + 1; else r = mid - 1; } for(register int i = 1, j = i + res - 1; j <= n; ++i, ++j) if(query(i, j) == yreuq(i, j)) ans[++tot] = i; printf("%d %d\n",tot, res - 1); for(register int i = 1; i <= tot; ++i) printf("%d ", ans[i]); return 0; }