1. 程式人生 > 其它 >Codeforces Round #745 Div.2 A~C

Codeforces Round #745 Div.2 A~C

A. CQXYM Count Permutations

求長度為\(2n\)的排列\(p\),且\(p\)中滿足\([p_i < p_{i+1}]\)的總對數不少於\(n\)的排列\(p\)的個數。

猜想:\(\frac 1 2(2n)!\)

證明:假定一個排列\(p\)\([p_i<p_{i+1}]\)的對數為\(k\),那麼對於排列\(q_i = 2n - p_i\),排列\(q\)\([q_i<q_{i+1}]\)的對數一定是\(2n - k - 1\)(被減後大小順序一定會發生改變)。因此類推下來\(k≥n\)的排列\(p\)的個數是總排列數的一半。

void solve() {
	int n;scanf("%d",&n);
	LL res = 1;
	for (int i = 3;i <= 2 * n;++i) {
		res = res * i % MOD;
	}
	printf("%lld\n",res);
}

B. Diameter of Graph

求頂點個數為\(n\),邊數為\(m\),直徑最大為\(k-2\)的無向連通圖是否合法(不允許有自環、重邊)。

首先考慮孤立點,\(n = 1\)時必須滿足\(m = 0\)\(k≥2\),否則不合法。

接著考慮一般情況,\(m<n-1\)圖不連通,\(m > n * (n-1) / 2\)的時候有重邊,\(k = 3\)的時候只能是\(m = n * (n-1)/2\),其他任何情況都能構造菊花圖使得直徑為2,最後只要不是孤立點,\(k>2\)

void solve() {
	LL n,m,k;
	cin >> n >> m >> k;
	
	k = k - 2;
	
	if (n == 1) {
		if (m != 0 || k < 0){
			cout << "NO\n";
		}else {
			cout << "YES\n";
		}
		return;
	}
	
	
	if (m > n * (n - 1) / 2 || k <= 0 || m < n - 1) {
		cout << "NO\n";
	}else if (k == 1 && m != (n - 1) * n / 2){
		cout << "NO\n";
	}else	cout << "YES\n";
}

C. Portal

題意讓你用黑曜石構造一個地獄傳送門。

可以列舉門的左上角和右下角,從而算出門需要的改變數。由於用1,0表示,我們可以直接用二維字首和求出線段的和與實際的差。

時間:\(O(n^4)\)

注意最後一重迴圈表示該門向右拓展的趨勢。那麼如果上左下中的該變數已經比最小值要大了,那麼此解一定不是答案,以此剪枝。

int a[405][405];
int pre[405][405];

int query(int j,int k,int l,int m) {
	return pre[l][m] - pre[j - 1][m] - pre[l][k-1] + pre[j-1][k-1];
}
void solve() {
	int n,m;
	scanf("%d%d",&n,&m);
	getchar();
	for (int i = 1;i <= n;++i) {
		for (int j = 1;j <= m;++j) {
			a[i][j] = getchar() - '0';
		}
		getchar();
	}
	
	for (int i = 1;i <= n;++i) {
		for (int j = 1;j <=m;++j) {
			pre[i][j] = pre[i - 1][j] + pre[i][j - 1] - pre[i - 1][j - 1] + a[i][j];
		}
	}
	
	int res = INF;
	
	for (int i = 1;i <= n;++i) {
		for (int j = 1;j <= m;++j) {
			for (int k = i + 4;k <= n;++k) {
				for (int l = j + 3;l <= m;++l) {
					int top = l-j-1 - query(i,j+1,i,l-1);
					int but = l-j-1 - query(k,j+1,k,l-1);
					int left = k-i-1 - query(i+1,j,k-1,j);
					int right = k-i-1 - query(i+1,l,k-1,l);
					int center = query(i+1,j+1,k-1,l-1);
					
					if (top + but + left + center >= res)	break;
					/*
					if (top + but + left + right + center < res) {
						cout << i << ' ' << j << endl;
						cout << k << ' ' << l << endl;
						cout << "top: " << top << endl;
						cout << "but: " << but << endl;
						cout << "left: " << left << endl;
						cout << "right: " << right << endl;
						cout << "center: " << center << endl;
					}
					*/
					res = min(res,top+but+left+right+center);
				}
			}
		}
	}
	printf("%d\n",res);
}