1. 程式人生 > >【CodeForces】CodeForces Round #516 (Div. 1) 題解

【CodeForces】CodeForces Round #516 (Div. 1) 題解

【比賽連結】

【題解連結】

**【A】**Oh Those Palindromes

【思路要點】

  • 一個字串是迴文串的一個必要條件是該字串的第一個字元與最後一個字元相同。
  • 因此,記字元 x x 出現的次數為 c
    n t x cnt_x
    ,一個字串迴文子串個數的上界為 i
    = a z ( c n
    t i + 1
    2
    )
    \sum_{i=a}^{z}\binom{cnt_i+1}{2}
    。而直接將字串的所有字元排序可以直接取到這個上界。
  • 因此,排序字串,輸出即可。
  • 時間複雜度 O ( N L o g N ) O(NLogN)

【程式碼】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
char s[MAXN];
int main() {
	int n; read(n);
	scanf("%s", s + 1);
	sort(s + 1, s + n + 1);
	printf("%s\n", s + 1);
	return 0;
}

**【B】**Labyrinth

【思路要點】

  • 假設一條路徑的起始點為 ( s x , s y ) (sx,sy) ,終點為 ( t x , t y ) (tx,ty) ,記其向左走的步數為 a a ,向右走的步數為 b b ,則 b a = t y s y b-a=ty-sy ,這意味著 b a b-a 是一個定值,因此,一條最小化 a + b a+b 的路徑同時也分別最小化了 a a b b
  • 在網格圖每一對上下的點間連長度為 0 0 的邊,每一對左右的點間連長度為 1 1 的邊,進行 B F S BFS ,並剔除移動次數超標的點即可。
  • 時間複雜度 O ( N 2 ) O(N^2)

【程式碼】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e3 + 5;
const int MAXQ = 8e6 + 5;
const int MIDQ = 4e6 + 2;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
char mp[MAXN][MAXN];
int x[MAXQ], y[MAXQ], ml[MAXQ], mr[MAXQ];
int main() {
	int n, m;
	read(n), read(m);
	int l = MIDQ, r = MIDQ;
	read(x[MIDQ]), read(y[MIDQ]);
	read(ml[MIDQ]), read(mr[MIDQ]);
	for (int i = 1; i <= n; i++)
		scanf("%s", mp[i] + 1);
	mp[x[MIDQ]][y[MIDQ]] = '*';
	int ans = 0;
	while (l <= r) {
		int nx = x[l], ny = y[l], tx, ty; ans++;
		int nml = ml[l], nmr = mr[l++];
		tx = nx - 1, ty = ny;
		if (mp[tx][ty] == '.') {
			l--, x[l] = tx, y[l] = ty;
			ml[l] = nml, mr[l] = nmr;
			mp[tx][ty] = '*';
		}
		tx = nx + 1, ty = ny;
		if (mp[tx][ty] == '.') {
			l--, x[l] = tx, y[l] = ty;
			ml[l] = nml, mr[l] = nmr;
			mp[tx][ty] = '*';
		}
		tx = nx, ty = ny - 1;
		if (nml != 0 && mp[tx][ty] == '.') {
			r++, x[r] = tx, y[r] = ty;
			ml[r] = nml - 1, mr[r] = nmr;
			mp[tx][ty] = '*';
		}
		tx = nx, ty = ny + 1;
		if (nmr != 0 && mp[tx][ty] == '.') {
			r++, x[r] = tx, y[r] = ty;
			ml[r] = nml, mr[r] = nmr - 1;
			mp[tx][ty] = '*';
		}
	}
	printf("%d\n", ans);
	return 0;
}

**【C】**Dwarves, Hats and Extrasensory Abilities

【思路要點】

  • 不妨將黑點劃分在左側,白點劃分在右側。
  • 令當前中間區間為 [ l , r ] [l,r] m i d = l + r 2 mid=\frac{l+r}{2} ,若 m i d mid 是黑點,我們令中間區間為 [ m i d , r ] [mid,r] ,否則,我們令中間區間為 [ l , m i d ] [l,mid]
  • 上述策略可以處理 N L o g 2 1 0 9 N≤Log_210^9 的情況。
  • 選擇兩條不相交的直線進行上述演算法,最後取中間區間中的一個點相連得到所求直線,這樣就可以處理 N 2 L o g 2 1 0 9 N≤2*Log_210^9 的情況了。
  • 時間複雜度 O ( N ) O(N)

【程式碼】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
int main() {
	int n; read(n);
	int al = 0, ar = 1e9;
	int bl = 0, br = 1e9;
	for (int i = 1; i <= n; i++) {
		char s[15];
		if (i & 1) {
			int mid = (al + ar) / 2;
			cout << 0 << ' ' << mid << endl;
			scanf("%s", s);
			if (s[0] == 'b') al = mid;
			else ar = mid;
		} else {
			int mid = (bl + br) / 2;
			cout << 1 << ' ' << mid << endl;
			scanf("%s", s);
			if (s[0] == 'b') bl = mid;
			else br = mid;
		}
	}
	cout << 0 << ' ' << (al + ar) / 2 << ' ' << 1 << ' ' << (bl + br) / 2 << endl;
	return 0;
}

**【D】**Candies for Children

【思路要點】

  • 設定閾值 α = O ( K ) \alpha=O(\sqrt{K})
  • N α N≤\alpha ,我們可以列舉走一圈使用的糖果數,並簡單判斷其合法性。
  • N &gt; α N&gt;\alpha ,我們可以列舉走的圈數 k k ,設 x x [ l , r ] [l,r] 2 2 的個數, y y 為其他 2 2 的個數, l e n len [ l , r ] [l,r] 的長度,有:
    1 1 2 ( k + 1 ) x + ( k + 1 ) ( l e n x ) + 2 k y + k ( N l e n y ) = K 2(k+1)x+(k+1)(len-x)+2ky+k(N-len-y)=K
    其中 ( x , y N , x [ 0 , l e n ] , y [ 0 , N l e n ] ) (x,y\in N,x\in[0,len],y\in[0,N-len])
    2 2 2 ( k + 1 ) x + ( k + 1 ) ( l e n x ) + 2 k y + k ( N l e n y ) = K 1 2(k+1)x+(k+1)(len-x)+2ky+k(N-len-y)=K-1
    其中 ( x , y N , x [ 1 , l e n ] , y [ 0 , N l e n ] ) (x,y\in N,x\in[1,len],y\in[0,N-len])