Codeforces Round #697 (Div. 3)A~G解题报告
Codeforces Round #697 (Div. 3)A~G解題報告
題 A Odd Divisor
題目介紹
解題思路
乍一想本題,感覺有點(diǎn)迷迷糊糊,但是證難則反,直接考慮沒有奇數(shù)因子的情況,即 N = 2i2^{i}2i,那么當(dāng)N != 2i2^i2i時,就有 奇數(shù)因子
注意使用 LL
AC代碼
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std;typedef long long LL;bool Check(LL x) {while (x != 1){if (x & 1){return true;}x >>= 1;}return false; }int main() {LL n;int t;cin >> t;while (t -- ){scanf("%lld", &n);if (Check(n)){cout << "YES" << endl;}else{cout << "NO" << endl;}}return 0; }題 B New Year’s Number
題目介紹
解題思路
直接就是一個 dp裸題,倘若 x 是2021 與 2020 的若干和,那么 x == 2020 或 x ==2021或者x - 2020 滿足要求 或者 x - 2021滿足要求
有了上述的遞推公式,直接開bool數(shù)組進(jìn)行動態(tài)規(guī)劃即可
AC代碼
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std;typedef long long LL; const int N = 1000010; bool st[N];int main() {int n;int t;cin >> t;st[2020] = st[2021] = true;for (int i = 2023; i < N; i ++ ){st[i] = st[i - 2021] | st[i - 2020];}while (t -- ){scanf("%d", &n);if (st[n]){cout << "YES\n";}else{cout << "NO\n";}}return 0; }題 C Ball in Berland
題目介紹
解題思路
同樣是直接統(tǒng)計不太方便,我們直接反向思考,計算出總方案數(shù)量,減去不合法方案數(shù)量,得到結(jié)果
總方案數(shù)量 = k * (k - 1) / 2
不合法方案數(shù)量 = 同一個男生被選中兩次 + 同一個女生被選中兩次
記得開 LL
AC代碼
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std;typedef long long LL; const int N = 200010; int boy_cnt[N], girl_cnt[N]; int n, m, k;int main() {int t;cin >> t;LL res = 0;while (t -- ){scanf("%d%d%d", &n, &m, &k);res = LL(k) * (k - 1);memset(boy_cnt, 0, sizeof boy_cnt);memset(girl_cnt, 0, sizeof girl_cnt);for (int i = 1; i <= k; i ++ ){static int tmp;scanf("%d", &tmp);boy_cnt[tmp] ++;}for (int i = 1; i <= k; i ++ ){static int tmp;scanf("%d", &tmp);girl_cnt[tmp] ++;}for (int i = 1; i <= n; i ++ ){res -= LL(boy_cnt[i]) * (boy_cnt[i] - 1);}for (int i = 1; i <= m; i ++ ){res -= LL(girl_cnt[i]) * (girl_cnt[i] - 1);}/// cout << "#############\n";printf("%lld\n", res / 2);/// cout << res / 2 << endl;}return 0; }題 D Cleaning the Phone
題目介紹
解題思路
錯誤思路
本來將題目想成了 dp 進(jìn)行求解,直接超時沒商量,考慮一下復(fù)雜度,確實有問題
O(N*2N)太大
正解
這個題目應(yīng)該進(jìn)行貪心的,先處理出來bib_ibi?=1數(shù)組,bib_ibi?=2數(shù)組,然后對數(shù)組可以清空的內(nèi)存進(jìn)行排序。
排序后進(jìn)行求取數(shù)組的前綴和,方便我們下面兩種做法降低復(fù)雜度。
下面有兩種問題的求解辦法,
方法一、二分
對于 對于 每個 bib_ibi?=1的下標(biāo)進(jìn)行枚舉,然后對 bib_ibi?=2數(shù)組進(jìn)行二分,查找到滿足釋放內(nèi)存的最小前綴數(shù)組的下標(biāo)。 O(Nlog(N))O(Nlog(N))O(Nlog(N))
方法二、雙指針
先找到一個合法解,然后數(shù)組下標(biāo)進(jìn)行移動,另一個指針作相應(yīng)的調(diào)整即可。O(N)O(N)O(N)
但是算上排序,最終復(fù)雜度為 O(Nlog(N))O(Nlog(N))O(Nlog(N))
但是本題有一個最狗的地方,cmp函數(shù)被卡了,可以直接寫歸并排序,或者cmp函數(shù)別寫等號,否則會超時
AC代碼
雙指針
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std;typedef long long LL;const int N = 200010, INF = 0x3f3f3f3f; LL a[N]; LL c[N], d[N]; LL n, m; int idx1, idx2;bool cmp(LL x, LL y){ return x > y; } void show() {for (int i = 1; i <= idx1; i ++ ) cout << c[i] << " "; cout << endl;for (int i = 1; i <= idx2; i ++ ) cout << d[i] << " "; cout << endl; }int main() {int T; cin >> T;while (T -- ){scanf("%lld %lld", &n, &m);for (LL i = 1; i <= n; i ++ )scanf("%lld", &a[i]);c[0] = d[0] = 0LL;idx1 = idx2 = 0;for (LL i = 1, b; i <= n; i ++ ){scanf("%lld", &b);if (b & 1) c[++ idx1] = (a[i]);else d[++ idx2] = (a[i]);}sort(c + 1, c + idx1 + 1, cmp);sort(d + 1, d + idx2 + 1, cmp);/// show();for (int i = 1; i <= idx1; i ++ ) c[i] += c[i - 1];for (int i = 1; i <= idx2; i ++ ) d[i] += d[i - 1];/// show();if (c[idx1] + d[idx2] < m){printf("-1\n");}else{int i, j, res = INF;for (i = 0; i <= idx1; i ++ ) // 尺取法的起點(diǎn)if (c[i] + d[idx2] >= m) // c[i] 的開頭break;j = idx2;res = min(res, i + j + j);// 此時i, j可以進(jìn)行 尺取法 了while (i <= idx1 && j >= 0){while (j >= 0 && i <= idx1 && c[i] + d[j] < m){i ++;}if (i <= idx1 && j >= 0)res = min(res, i + j + j);while (i <= idx1 && j >= 0 && c[i] + d[j] >= m){if (i <= idx1 && j >= 0)res = min(res, i + j + j);j --;}}if (res == INF) res = -1;printf("%d\n", res);}}return 0; }二分
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std;typedef long long LL; const int N = 200010, INF = 0x3f3f3f3f; int n, m; int a[N]; LL c[N], d[N]; int szc, szd;bool cmp(LL a, LL b) {return a > b; } int main() {int T; cin >> T;while (T -- ){static int b;cin >> n >> m;for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);c[0] = d[0] = szc = szd = 0;for (int i = 1; i <= n; i ++ ){scanf("%d", &b);if (b & 1)c[++ szc] = a[i];elsed[++ szd] = a[i];}sort(c + 1, c + szc + 1, cmp);sort(d + 1, d + szd + 1, cmp);for (int i = 1; i <= szc; i ++ ) c[i] += c[i - 1];for (int i = 1; i <= szd; i ++ ) d[i] += d[i - 1];if (c[szc] + d[szd] < m){puts("-1");}else{int res = INF;for (int i = 0; i <= szc; i ++ ){if (c[i] + d[szd] < m)continue;else if (c[i] >= m){res = min(res, i);break;}else{static int tmp;tmp = lower_bound(d + 1, d + 1 + szd, m - c[i]) - d;res = min(res, tmp + tmp + i);}}cout << res << endl;}}return 0; }題 E Advertising Agency
題目介紹
解題思路
肯定是先對 博主的 粉絲數(shù)量進(jìn)行排序,貪心的請博主即可,這個題目主要是求解 排列組合問題。
CijC_i^jCij?=Ci?1jC_{i-1}^jCi?1j?+Ci?1j?1C_{i-1}^{j-1}Ci?1j?1?
利用dp直接進(jìn)行求解,關(guān)鍵是初始化寫好就可以了 CiiC_i^iCii?=Ci0C_i^0Ci0?=1
AC代碼
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std;typedef long long LL; const int N = 1010, INF = 0x3f3f3f3f; const int MOD = 1e9 + 7; int n, k; int a[N]; int f[N][N];bool cmp(LL a, LL b) {return a > b; }int main() {memset(f, 0, sizeof f);for (int i = 0; i < N; i ++ )f[i][i] = f[i][0] = 1;for (int i = 1; i < N; i ++ )for (int j = 1; j <= i; j ++ )f[i][j] = (f[i - 1][j] + f[i - 1][j - 1]) % MOD;int T; cin >> T;while (T -- ){cin >> n >> k;for (int i = 1; i <= n; i ++ )scanf("%d", &a[i]);sort(a + 1, a + n + 1, cmp);static int x, sidx, eidx;x = a[k], sidx = -1, eidx = -1;for (int i = 1; i <= n; i ++ ){if (a[i] == x){if (sidx == -1) sidx = i;eidx = i;}}cout << f[eidx - sidx + 1][k - sidx + 1] << endl;}return 0; }題 F Unusual Matrix
題目介紹
解題思路
題目問的是能否從 An?nA_{n*n}An?n?矩陣轉(zhuǎn)換到 Bn?nB_{n*n}Bn?n?矩陣,由轉(zhuǎn)換的性質(zhì),同一個行/列轉(zhuǎn)換兩次是沒有任何作用的,因此我們枚舉第一行需要操作/與不需要操作,那么第一行的元素能操作的對象只有列,因此列是否需要操作就得以確定,列確定,那么,反過來行也就得以確定,最終得到結(jié)果。
AC代碼
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std;typedef long long LL; const int N = 1010, INF = 0x3f3f3f3f; const int MOD = 1e9 + 7; int n; char a[N][N], b[N][N]; char c[N][N];inline void Change(char c[][N], int x, bool row); bool Same(char c[][N], char d[][N], int x) {for (int i = 1; i <= n; i ++ )if (c[x][i] != d[x][i])return false;return true; }bool Check(char c[][N], char d[][N]) {// 第一行是不需要動的,我們看看 列 的影響for (int i = 1; i <= n; i ++ )if (c[1][i] != d[1][i])Change(c, i, false);for (int i = 2; i <= n; i ++ ){if (c[i][1] != d[i][1]) // 修改 行Change(c, i, true);if (!Same(c, d, i))return false;}return true; } inline void Change(char c[][N], int x, bool row) {if (row) // rowfor (int i = 1; i <= n; i ++ ){c[x][i] = 97 - c[x][i]; // 48 + 49 - c[i]}else // colfor (int i = 1; i <= n; i ++ ){c[i][x] = 97 - c[i][x]; // 48 + 49 - c[i]} }int main() {int T; cin >> T;while (T -- ){cin >> n;for (int i = 1; i <= n; i ++ )scanf("%s", a[i] + 1);for (int i = 1; i <= n; i ++ )scanf("%s", b[i] + 1);memcpy(c, a, sizeof c);if (Check(c, b) || (memcpy(c, a, sizeof c), Change(c, 1, true), Check(c, b)))puts("YES");elseputs("NO");}return 0; }題 G Strange Beauty
題目介紹
解題思路
這個題目是一個比較巧妙地dp題目,對于一個 BeutifulArrayBeutiful ArrayBeutifulArray我們將其非降序排序之后可以發(fā)現(xiàn),后面的數(shù)字都是可以整除前面的,這是一個充分必要的條件
那么最長的數(shù)組對應(yīng)著最長的整除序列
而且還有 一個坑點(diǎn),雞兒數(shù)字還可能相等,也就是我們需要先預(yù)處理出 XXX出現(xiàn)的次數(shù)
定義一個數(shù)組 fif_ifi?表示,以數(shù)字 i 作為最大值,可以構(gòu)成 BeautifulArrayBeautifulArrayBeautifulArray的最大長度,
fif_ifi? = iii出現(xiàn)次數(shù)+maxmaxmax{因子的 j 的fjf_jfj?}
下面是dp過程,而且為了方便書寫,降低時間復(fù)雜度,直接將因子的相加寫入了 因子的循環(huán)中
AC代碼
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std;typedef long long LL; const int N = 200010, INF = 0x3f3f3f3f;int cnt[N]; int a[N]; bool st[N]; int f[N]; int n;int main() {int T; cin >> T;while (T -- ){static int res;cin >> n;for (int i = 1; i <= n; i ++ )scanf("%d", &a[i]);res = INF;sort(a + 1, a + 1 + n);memset(cnt, 0, sizeof cnt);memset(st, false, sizeof st);memset(f, 0, sizeof f);for (int i = 1; i <= n; i ++ ) cnt[a[i]] ++;for (int i = 1, val; i <= n; i ++ ){val = a[i];if (st[val]) continue;st[val] = true;// cnt[val] = max(cnt[val], 1);f[val] = f[val] + cnt[val]; // 給自己加的for (int j = val + val; j < N; j += val){f[j] = max(f[j], f[val]); // 給別的數(shù)字加的}res = min(res, n - f[val]);}cout << res << endl;}return 0; }本次CF小結(jié)
- 小心快排可能被卡,導(dǎo)致超時,可以通過 修改cmp函數(shù),或者是直接使用 歸并排序來解決
- 其次,考慮問題的時候,尤其是數(shù)量的問題,可以使用容斥定理,證難則反
- 貪心、結(jié)合二分、或者是雙指針來優(yōu)化復(fù)雜度,有時候考慮dp背包復(fù)雜度太高
- 求解組合數(shù)的常用方法要記住, dp,逆元,盧卡斯定理
總結(jié)
以上是生活随笔為你收集整理的Codeforces Round #697 (Div. 3)A~G解题报告的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java部署jar还是war优劣_详解S
- 下一篇: python 强制结束线程_在pytho