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);
}
posted @ 2021-10-01 17:44  AlexanderZ.Tang  阅读(122)  评论(0)    收藏  举报