2019.10.26模擬賽

T1 序列

給定一長度爲\(n\)的序列\(s\),定義其健美值爲:$$\sum\limits_{i=1}^{n}|s_i - i|$$由於 zzq 喜歡健美,因此 zzq 但願減少\(s\)的健美值,以陪襯 zzq 的健美。爲了達到 zzq 的目的,zzq 但願你對序列進行旋轉操做,一次旋轉操做可使序列中的全部元素前移一位,並使\(s_1\)移動到\(s_n\)
能夠進行任意次旋轉操做,zzq 但願旋轉後的健美值最小,請找出這個最小值。spa

SOV

智商檢測題
咱們發現對於每一個數,移動每一次會使本來差小於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;
}

T3 動態數點

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

SOV

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;
}
相關文章
相關標籤/搜索