寒假訓練第十二天-Codeforces Round #697 (Div. 3)
寒假訓練第十二天-Codeforces Round #697 (Div. 3)
前言:心態出了些問題就鴿了兩天,還是繼續訓練吧。打了一場div3,然後就unrated了,發揮也挺糟糕的。
題目連結-https://codeforces.com/contest/1475
A-Odd Divisor
題意:問一個數是否有大於1的奇因子。
題解:很明顯奇數肯定有奇因子(本身),偶數則有兩種情況一種是2^d不含奇因子的,其他的則必定含奇因子(一直除以2肯定會出現奇數)。
int32_t main()
{
ICO;
ll t, n;
cin >> t;
while(t--)
{
cin >> n;
if(n & 1) cout << "YES" << endl;
else
{
if(n & (n - 1)) cout << "YES" << endl;
else cout << "NO" << endl;
}
}
return 0;
}
B-New Year’s Number
題意:給你一個數,問是否可以拆成n * 2020 + m * 2021(n,m可為0)。
題解:暴力標記所有可拆成n * 2020 + m * 2021的數,然後O(1)查詢即可。
const int maxn = 1e6 + 10;
bool ok[maxn];
int32_t main()
{
ICO;
ll t, n;
for(int i = 0; i <= 1000; i++)
{
for(int j = 0; j <= 1000; j++)
{
int a = 2020 * i + j * 2021;
if(a > 1000000) continue;
ok[a] = 1;
}
}
cin >> t;
while(t--)
{
cin >> n;
if(ok[n]) cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}
C-Ball in Berland
題意:給你n組數,每組數有兩個數(第一個數和第二個數),現讓你從n組數中任選兩組,需要保證選擇的兩組中每一組和第二組的第一個數和第一個數不同,第二個數和第二個數不同(第一個數可以和第二個數相同)。問你有多少種選擇的方案,輸出方案數。
題解:我們可以先以第一個數為基準求出所有的方案數,然後我們去考慮第二個數相同造成的影響,再減去影響即可。
const int maxn = 2e5 + 10;
int ok1[maxn], book[maxn], ok2[maxn];
ll c[maxn];
int32_t main()
{
ICO;
for(int i = 1; i <= 200000; i++)
c[i] = i * (i - 1) / 2;
int t, n;
cin >> t;
while(t--)
{
int a, b, k, x;
cin >> a >> b >> k;
for(int i = 1; i <= k; i++)
{
cin >> x;
ok1[x]++;
}
ll sum = 0, res = 0;
for(int i = 1; i <= a; i++)
{
book[i] = ok1[i] * (k - ok1[i]) - sum * ok1[i];
sum += ok1[i];
res += book[i];
}
for(int i = 1; i <= k; i++)
{
cin >> x;
ok2[x]++;
}
for(int i = 1; i <= b; i++) {if(ok2[i] > 1) res -= (c[ok2[i]]);}
cout << res << endl;
for(int i = 1; i <= a; i++) ok1[i] = book[i] = 0;
for(int i = 1; i <= b; i++) ok2[i] = 0;
}
return 0;
}
D-Cleaning the Phone
題意:一個東西有兩個屬性:價值和代價。現在有n件物品,給你一個最小价值的限制,問滿足次限制的最小代價是多少。
題解:由題意我們發現代價只有1和2,那我們就按代價將價值分成兩份(a 和 b),然後貪心去處理(要排序),貪心的準則為:開始先取a中的所有物品,b的物品都不取,然後放棄a中價值最小的去取b中價值最大的(一直取直到滿足限制再記錄代價),迴圈往復,直至a中物品全被丟棄,輸出此過程中最小代價即可。
const int maxn = 2e5 + 10;
int a[maxn], b[maxn];
vector<int> v1, v2;
int32_t main()
{
ICO;
int t, n, m;
cin >> t;
while(t--)
{
cin >> n >> m;
ll sum = 0;
for(int i = 1; i <= n; i++) {cin >> a[i]; sum += a[i];}
for(int i = 1; i <= n; i++) cin >> b[i];
if(sum < m) {cout << -1 << endl; continue;}
for(int i = 1; i <= n; i++)
{
if(b[i] == 1) v1.push_back(a[i]);
else v2.push_back(a[i]);
}
sort(v1.rbegin(), v1.rend());
sort(v2.begin(), v2.end());
sum = 0;
for(int i = 0; i < v2.size(); i++) sum += v2[i];
int p = 0, res = inf_int;
for(int i = 0; i <= v2.size(); i++)
{
while(p < v1.size() && sum < m) sum += v1[p++];
if(sum >= m) res = min(res, (int (v2.size() - i) << 1) + p);
if(i < v2.size())sum -= v2[i];
}
cout << res<< endl;
v1.clear(), v2.clear();
}
return 0;
}
E-Advertising Agency
題意:從n個數中選擇k個數,使權值最大,問選擇方案數(取模後)。
題解:我們將權值從大到小排序,很明顯方案數是和第k個數相等的數的個數決定的,則我們需要求的就是從所有和第k個數相等的數中取若干個數(前面已經選擇了多少數),即組合。由資料範圍觀察暴力記錄楊輝三角也行,下面給出楊輝三角和盧卡斯兩份程式碼。
//楊輝三角
const int maxn = 1e3 + 10;
const int mod = 1e9 + 7;
int a[maxn], ok[maxn];
int c[maxn][maxn];
int32_t main()
{
ICO;
c[0][0] = 1;
for(int i = 1; i <= 1000; i++)
{
c[i][0] = 1;
for(int j = 1; j <= i; j++)
c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
}
int t, n, k;
cin >> t;
while(t--)
{
cin >> n >> k;
for(int i = 1; i <= n; i++) {cin >> a[i]; ok[a[i]]++;}
sort(a + 1, a + 1 + n, greater<int>() );
int cnt = 0;
for(int i = 1; i <= k; i++)
if(a[i] == a[k]) {cnt = i - 1; break;}
ll res = c[ok[a[k]]][min(k - cnt, ok[a[k]] - (k - cnt))];
cout << res << endl;
for(int i = 1; i <= n; i++) ok[a[i]] = 0;
}
return 0;
}
//盧卡斯
const int maxn = 1e3 + 10;
const int mod = 1e9 + 7;
ll pow(ll a, ll b, ll m)
{
ll ans = 1;
a %= m;
while(b)
{
if(b & 1)ans = (ans % m) * (a % m) % m;
b /= 2;
a = (a % m) * (a % m) % m;
}
ans %= m;
return ans;
}
ll inv(ll x)
{
return pow(x, mod - 2, mod);
}
ll C(ll n, ll m)
{
if(m > n)return 0;
ll up = 1, down = 1;
for(int i = n - m + 1; i <= n; i++)up = up * i % mod;
for(int i = 1; i <= m; i++)down = down * i % mod;
return up * inv(down) % mod;
}
ll Lucas(ll n, ll m)
{
if(m == 0)return 1;
return C(n % mod, m % mod) * Lucas(n / mod, m / mod) % mod;
}
int a[maxn], ok[maxn];
int32_t main()
{
ICO;
int t, n, k;
cin >> t;
while(t--)
{
cin >> n >> k;
for(int i = 1; i <= n; i++) {cin >> a[i]; ok[a[i]]++;}
sort(a + 1, a + 1 + n, greater<int>() );
int cnt = 0;
for(int i = 1; i <= k; i++)
if(a[i] == a[k]) {cnt = i - 1; break;}
ll res = Lucas(ok[a[k]], min(k - cnt, ok[a[k]] - (k - cnt)));
cout << res << endl;
for(int i = 1; i <= n; i++) ok[a[i]] = 0;
}
return 0;
}
總結:感覺打了兩週cf提升也不大,還是要把重心放到學演算法上,刷題成為輔助。