Codeforces Round #745 Div.2 A~C
阿新 • • 發佈:2021-10-01
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); }