Codeforces Round #828 (Div. 3)練習筆記

\(\text{A.Number Replacement}\)

給定長度爲 \(n(n\leq 50)\) 的整數數組 \(a(a_i\leq 50)\) 和一個長度爲 \(n\) 的字符串 \(s\)
定義一次操作爲:選定整數 \(x\) 和字符 \(c\) ,將數組所有等於 \(x\) 的位置變成 \(c\) 。問是否能通過多次操作將 \(a\) 變爲 \(s\)\(T(T\leq 1000)\) 組數據。
\(\text{sol.}\) 注意到 \(a_i\) 很小,所以可以從左往右掃一遍,記錄 \(id_{a_i}=s_i\) 。若當前 \(id_{a_i}\) 已經有值了且值不等於 \(s_i\) ,則無法將 \(a\) 變爲 \(s\)

cint maxn = 60;
int T, n, a[maxn], id[maxn], fl;
char s[maxn];
int main(){
	T = rd();
	while(T--){
		n = rd(), fl = 0;
		fp(i, 1, n)a[i] = rd(), id[a[i]] = -1;
		scanf("%s", s+1);
		fp(i, 1, n){
			if(~id[a[i]] && id[a[i]] != s[i]-'a'){ fl = 1; break; }
			id[a[i]] = s[i]-'a';
		}
		puts(fl ? "NO" : "YES");
	}
	return 0;
}

\(\text{B. Even-Odd Increments}\)

給定長度爲 \(n(n\leq 10^5)\) 的數組 \(a(a_i\leq 10^9)\) ,接下來有 \(q(q\leq 10^5)\) 次操作,每次操作將數組裏的所有奇數或者所有偶數都加上某個值 \(([1,10^4])\) 。要求在每次操作後輸出整個數組的和。多組數據。
直接記錄一下現在數組裏有多少個奇數、多少個偶數,每次操作的時候答案的改變值就可以直接計算出來。如果加的數是奇數,則需要修改一下奇數和偶數的個數。

cint maxn = 100010;
int T, n, q, a[maxn], cnt[2];
LL ans;
int main(){
	T = rd();
	while(T--){
		n = rd(), q = rd(), ans = cnt[0] = cnt[1] = 0;
		fp(i, 1, n)a[i] = rd(), ++cnt[a[i]&1], ans += a[i];
		while(q--){
			rg int typ = rd(), x = rd();
			ans += 1ll*cnt[typ]*x;
			if(x&1)cnt[!typ] += cnt[typ], cnt[typ] = 0;
			printf("%lld\n", ans);
		}
	}
	return 0;
}

\(\text{C. Traffic Light}\)

給定一個長度爲 \(n(n\leq 2\times 10^5)\) 的只包含 \(\text{r,y,g}\)環形字符串,再給定一個 \(\text{r,y,g}\) 中的字符 \(c\) 。定義 \(f_i\) 表示第 \(i\) 個字符後面最近的 \(\text g\)\(i\) 的距離。對於所有字符 \(c\) ,求出 \(f\) 的最大值。多組數據。
按照翻譯後的題意做就行。處理環形字符串可以直接複製一遍接在後面。

cint maxn = 200010;
int T, n, nxt[maxn<<1], pos, ans;
char now, s[maxn<<1];
int main(){
	scanf("%d", &T);
	while(T--){
		scanf("%d %c", &n, &now), scanf("%s", s+1), pos = n<<1|1, ans = 0;
		fp(i, 1, n)s[n+i] = s[i];
		fb(i, n<<1, 1){
			if(s[i] == 'g')pos = i;
			nxt[i] = pos;
		}
		fp(i, 1, n)if(s[i] == now && nxt[i]-i > ans)ans = nxt[i]-i;
		printf("%d\n", ans);
	}
	return 0;
}

\(\text{D. Divisibility by 2^n}\)

給定一個長度爲 \(n(n\leq 2\times 10^5)\) 的數組 \(a(a_i\leq 10^9)\) 。定義一次操作爲將某個 \(a_i\) 變成 \(a_i\times i\) 。每個 \(i\) 只能被操作 \(1\) 次。求最少需要多少次操作,使得 \(2^n | \prod_{i=1}^n a_i\) 。多組數據。
首先求出 \(\prod_{i=1}^n a_i\) 中有多少個 \(2\) 相乘,假設有 \(m\) 個。然後將 \(1\)~\(n\) 中每個數的 \(2\) 次冪分離出來,並從大到小排序。按照 \(2\) 次冪的大小從大到小依次加入每個數的 \(2\) 次冪,一旦加起來大於等於 \(n-m\) 次就停止。此時加了多少次就是最少的操作次數。

cint maxn = 200010;
int T, n, a[maxn], f[maxn], sum, cnt;
int main(){
	T = rd();
	while(T--){
		n = rd(), sum = cnt = 0;
		fp(i, 1, n){
			a[i] = rd();
			rg int x = a[i];
			while(x && x%2 == 0)x >>= 1, ++sum;
		}
		fp(i, 1, n){
			f[i] = 0;
			rg int x = i;
			while(x && x%2 == 0)x >>= 1, ++f[i];
		}
		sort(f+1, f+1+n), reverse(f+1, f+1+n);
		while(cnt < n && sum < n)sum += f[++cnt];
		if(sum < n)puts("-1");
		else printf("%d\n", cnt);
	}
	return 0;
}

\(\text{E. Divisible Numbers}\)

給定 \(4\) 個數 \(a,b,c,d(1\leq a<c\leq 10^9,1\leq b<d\leq 10^9)\) 。求出 \(x,y\) ,滿足 \(a<x\leq c,b<y\leq d\) 並且 \(ab|xy\)\(T(T\leq 10)\) 組數據。
\(x,y\) 都可以寫成 \(a\) 的因數 \(\times\) \(b\) 的因數 \(\times\) 一個係數的形式。注意到一個數的因數個數很少,所以可以枚舉一個 \(a\) 的因數 \(f_1\) ,再枚舉一個 \(b\) 的因數 \(f_2\) ,那麼 \(x=k_1f_1f_2,y=k_2\times \frac{ab}{f_1f_2}\) 。只需要求出 \(k_1,k2\) 使得 \(x,y\) 在題目要求的範圍即可。

cint maxn = 100010;
int T, a, b, c, d, f[2][maxn], cnt[2], fl;
int main(){
	T = rd();
	while(T--){
		a = rd(), b = rd(), c = rd(), d = rd(), fl = cnt[0] = cnt[1] = 0;
		for(rg int i = 1; i*i <= a; ++i)if(a%i == 0){
			f[0][++cnt[0]] = i;
			if(i*i != a)f[0][++cnt[0]] = a/i;
		}
		for(rg int i = 1; i*i <= b; ++i)if(b%i == 0){
			f[1][++cnt[1]] = i;
			if(i*i != b)f[1][++cnt[1]] = b/i;
		}
		fp(i, 1, cnt[0])if(!fl)fp(j, 1, cnt[1]){
			rg LL x = 1ll*f[0][i]*f[1][j];
			rg LL y = 1ll*a*b/x;
			x = a/x*x+x, y = b/y*y+y;
			if(a < x && x <= c && b < y && y <= d){ printf("%lld %lld\n", x, y), fl = 1; break; }
		}
		if(!fl)puts("-1 -1");
	}
	return 0;
}

\(\text{F. MEX vs MED}\)

給定一個長度爲 \(n(n\leq 2\times 10^5)\) 的由 \(0\)~\(n-1\) 的排列 \(p\)
定義 \(\text{mex}\) 爲數列中最小的未出現的非負整數。
定義 \(\text{med}\) 爲數列的中位數(若長度爲偶數,則取第 \(\frac{len}{2}\) 小的數)。
求出有多少個區間滿足 \(\text{mex} > \text{med}\) 。多組數據。
假設一個區間的 \(\text{mex}=m\) ,那麼這個區間中就得出現 \([0,m-1]\) 中所有的數。由此可以得出,區間長度不能超過 \(2m\) ,否則 \(\text{med}\) 將大於 \(m\)
所以我們可以枚舉 \(m\) ,維護最小的包含了 \([0,m-1]\) 所有數的區間。接下來考慮拓展這個區間。必然是某一個方向拓展到 \(m\) 所在位置,另一個方向拓展到數組盡頭,所以直接計算有多少個滿足條件的區間即可。
計算時可以直接枚舉 \(m\) 所在的那一邊的長度,這樣可以保證複雜度是線性的。

cint maxn = 200010;
int T, n, p[maxn], pos[maxn], l, r, mex, rst;
LL ans;
int main(){
	T = rd();
	while(T--){
		n = rd(), ans = 0;
		fp(i, 1, n)p[i] = rd(), pos[p[i]] = i;
		l = n+1, r = 0, mex = 0;
		fp(i, 0, n-1){
			if(l <= pos[i] && pos[i] <= r)continue;
			if(pos[i] < l)l = pos[i];
			if(pos[i] > r)r = pos[i];
			while(mex < n && l <= pos[mex] && pos[mex] <= r)++mex;
			if(mex == n)break;
			rst = mex*2-(r-l+1);
			if(pos[mex] < l)fp(i, pos[mex]+1, l)ans += max(0, min(n-r+1, rst-(l-i)+1));
			else fp(i, r, pos[mex]-1)ans += max(0, min(l, rst-(i-r)+1));
		}
		printf("%lld\n", ans+1);
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章