题意:有一群小朋友围成一个环,编号1,2,3…N。每个人手上握着一个非0的数字,首先第K个人出列,然后看他手上的数字,假设为m,则从下一个开始第m个人出列,一直如此。并设i为小于等于N的最大反素数,问第i个出列的人得编号,i的约数个数。(设g(i)为i的约数的个数,若任意j<i,都有g(j)<g(i)则i为反素数)。
首先要得到[0,N]的最大反素数(怎么得到下面再说),然后模拟出列操作,用线段树来优化使得每次出列在O(logN)时间内完成。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; #define maxn 100005 int maxsub[maxn<<2], minsub[maxn<<2]; int lmax[maxn<<2], rmax[maxn<<2]; int lmin[maxn<<2], rmin[maxn<<2]; int sum[maxn<<2]; void PushUp(int rt) { int l = rt<<1; int r = l+1; sum[rt] = sum[l] + sum[r]; maxsub[rt] = max(max(maxsub[l], maxsub[r]), rmax[l]+lmax[r]); minsub[rt] = min(min(minsub[l], minsub[r]), rmin[l]+lmin[r]); lmax[rt] = max(lmax[l], sum[l]+lmax[r]); rmax[rt] = max(rmax[r], sum[r]+rmax[l]); lmin[rt] = min(lmin[l], sum[l]+lmin[r]); rmin[rt] = min(rmin[r], sum[r]+rmin[l]); } void build(int l, int r, int rt) { if (l == r) { scanf("%d", &sum[rt]); minsub[rt] = lmax[rt] = rmax[rt] = lmin[rt] = rmin[rt] = maxsub[rt] = sum[rt]; return; } int m = (l+r)>>1; build(l, m, rt<<1); build(m+1, r, rt<<1|1); PushUp(rt); } void update(int target, int val, int l, int r, int rt) { if (l == r) { sum[rt] = maxsub[rt] = minsub[rt] = val; lmax[rt] = rmax[rt] = lmin[rt] = rmin[rt] = val; return; } int m = (l+r)>>1; if (m >= target) update(target, val, l, m, rt<<1); else update(target, val, m+1, r, rt<<1|1); PushUp(rt); } int main() { int n, m, ans; scanf ("%d", &n); build(1, n, 1); scanf("%d", &m); while (m--) { int a, b; scanf ("%d%d", &a, &b); update(a, b, 1, n, 1); if (sum[1] == maxsub[1]) //序列全为非负数的时候 ans = sum[1] - minsub[1]; else ans = max(maxsub[1], sum[1]-minsub[1]); printf ("%d ", ans); } return 0; }