Codeforces Round #667 Div.3 (CF1409)
Div3,享受俯冲的快感
A:
给两个整数\(a\)和\(b\),你可以让$a \pm k (k \in [1, 10]) $,求最少操作次数。
签到题,直接给Code吧:
/*
ID: Loxilante
Time: 2020/09/04
Prog: CF1409A
Lang: cpp
*/
#ifdef ONLINE_JUDGE
#pragma GCC optimize("O3")
#endif
#include <bits/extc++.h>
#define rep(i, l, r) for(int i = l; i < r; i++)
#define hrp(i, l, r) for(int i = l; i <= r; i++)
#define rev(i, r, l) for(int i = r; i >= l; i--)
#define ms(n, t) memset(n, t, sizeof(n))
#define pb push_back
#define int ll
#ifndef JOEON
#define D(...) 97
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
template<typename tn = int> inline tn next(void) { tn k; cin>>k; return k; }
signed main(void)
{
#ifdef JOEON
// freopen("C:\\Users\\Joeon\\Desktop\\IN.txt", "r", stdin);
// freopen("C:\\Users\\Joeon\\Desktop\\OUT.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
int T = next();
while(T--)
{
int a, b;
cin>>a>>b;
if (a > b) swap(a, b);
cout<<(b-a)/10+(!!((b-a)%10))<<endl;
}
return 0;
}
B:
给定\(a, b, c, d, n\),你可以进行\(n\)次操作,在保证\(a >= c \&\& b >= d\)的情况下将\(a\)或\(b\)减\(1\),求\(ab\)最小值。
被这题吊打
一道有点思维难度的 Greedy ,可惜我没有思维,可以算出\(a\)的可能最小值\(e\)和\(b\)的可能最小值\(f\),选可能最小值更小的减去,如果\(n\)还没有用完就再减另外一个。
Code:
/*
ID: Loxilante
Time: 2020/09/04
Prog: CF1409B
Lang: cpp
*/
#ifdef ONLINE_JUDGE
#pragma GCC optimize("O3")
#endif
#include <bits/extc++.h>
#define rep(i, l, r) for(int i = l; i < r; i++)
#define hrp(i, l, r) for(int i = l; i <= r; i++)
#define rev(i, r, l) for(int i = r; i >= l; i--)
#define ms(n, t) memset(n, t, sizeof(n))
#define pb push_back
#define int ll
#ifndef JOEON
#define D(...) 97
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
template<typename tn = int> inline tn next(void) { tn k; cin>>k; return k; }
signed main(void)
{
#ifdef JOEON
// freopen("C:\\Users\\Joeon\\Desktop\\IN.txt", "r", stdin);
// freopen("C:\\Users\\Joeon\\Desktop\\OUT.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
int T = next();
while(T--)
{
int a, b, c, d, n;
cin>>a>>b>>c>>d>>n;
int e = max(c, a-n), f = max(d, b-n);
if (f > e)
swap(a, b), swap(c, d);
if (b-d <= n) n -= b-d, b = d;
else b -= n, n = 0;
a -= min(a-c, n);
cout<<a*b<<endl;
}
return 0;
}
C:
给定\(n, a, b\),构造一个最大值最小的长度为\(n\)的只包含正整数的等差数列w,使得\(a, b \in w\)。
难度不大, bf 即可,穷举在\(a, b\)之间元素的个数算出公差,再判断\(w\)中是否只包含正整数。
Code:
/*
ID: Loxilante
Time: 2020/09/04
Prog: CF1409C
Lang: cpp
*/
#ifdef ONLINE_JUDGE
#pragma GCC optimize("O3")
#endif
#include <bits/extc++.h>
#define rep(i, l, r) for(int i = l; i < r; i++)
#define hrp(i, l, r) for(int i = l; i <= r; i++)
#define rev(i, r, l) for(int i = r; i >= l; i--)
#define ms(n, t) memset(n, t, sizeof(n))
#define pb push_back
#define int ll
#ifndef JOEON
#define D(...) 97
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
template<typename tn = int> inline tn next(void) { tn k; cin>>k; return k; }
signed main(void)
{
#ifdef JOEON
// freopen("C:\\Users\\Joeon\\Desktop\\IN.txt", "r", stdin);
// freopen("C:\\Users\\Joeon\\Desktop\\OUT.txt", "w", stdout);
#endif
int T = next();
clock_t InputFinished = clock();
while(T--)
{
int n, a, b;
cin>>n>>a>>b;
rev(i, n-2, 0) if ((b-a)%(i+1) == 0)
{
int gc = (b-a)/(i+1);
int possiblePr = min((a-1)/gc, n-i-2);
int low = a-possiblePr*gc;
bool yes = 0;
rep(j, 0, n) { cout<<low<<" \n"[j == n-1], low += gc; yes = 1; }
if (yes) break;
}
}
return 0;
}
D:
给定正整数\(n,s\),令\(p = n+k\),并且\(p\)的各数位之和小于等于\(s\),求最小的\(k\)。
继续被吊打
本思路借鉴,因为写的真的好。
我们随便口胡一个 Greedy ,ezly得出\(p\)肯定是\(n\)的某一位的进位,这样我们枚举进位的位数,这道题就ezly解决了。
还有一些\(\color{orange}{Note}\):
-
不要用字符串来处理\(p\),我就是这样然后被虐了
-
这道题\(p\) \(\color{orange}{long long}\)装不下,所以我们可以用\(\color{orange}{unsigned long long}\)。
-
要特判\(n\)位数之和是不是已经小于\(s\)了,如果是那么直接输出\(0\)就ok啦。
Code:
/*
ID: Loxilante
Time: 2020/09/05
Prog: CF1409D
Lang: cpp
*/
#ifdef ONLINE_JUDGE
#pragma GCC optimize("O3")
#endif
#include <bits/extc++.h>
#define rep(i, l, r) for(int i = l; i < r; i++)
#define hrp(i, l, r) for(int i = l; i <= r; i++)
#define rev(i, r, l) for(int i = r; i >= l; i--)
#define ms(n, t) memset(n, t, sizeof(n))
#define pb push_back
#define int ll
#ifndef JOEON
#define D(...) 97
#endif
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
template<typename tn = int> inline tn next(void) { tn k; cin>>k; return k; }
signed main(void)
{
#ifdef JOEON
// freopen("C:\\Users\\Joeon\\Desktop\\IN.txt", "r", stdin);
// freopen("C:\\Users\\Joeon\\Desktop\\OUT.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
int T = next();
while(T--)
{
int n, s, ans = 0, all = 0;
cin>>n>>s;
int temp = n;
while(temp) all += temp%10, temp /= 10;
if (all <= s) { cout<<0<<endl; continue; }
for(ull mod = 1; mod <= n; mod *= 10)
{
int bitnum = n/mod%10;
if (!bitnum) continue;
// 当前位数为0,不需要进位
ans += (10-bitnum)*mod;
n += (10-bitnum)*mod;
// 进位
all = 0;
temp = n;
while(temp) all += temp%10, temp /= 10;
if (all <= s) break;
}
cout<<ans<<endl;
}
return 0;
}
E:
给你\(k\)和二维坐标\(n\)个点,你要放置两个长度为\(k\)的平台,放好后点会掉下来,求最多的落在平台上的点的个数。
不难发现\(y\)轴根本没用,因为你可以把平台放置在y轴的\(- \infty\)上。
也不难发现平台不重叠是最优的。
用最朴素的 bf 思想可以想出\(O(n^2)\)做法,先把点排序,遍历每一个点的\(x\)坐标,求出把平台左端放这儿能覆盖多少个点,答案是两个最大值之和。
可惜,\(O(n^2)\)会超时,这时我们考虑把一层\(O(n)\)给优化,让时间复杂度低于\(O(nlogn)\)。优化遍历点肯定无法做到,然则,我们可以优化求出把平台放这儿能覆盖多少个点。
既然已经排好了序,那数组就满足单调性,可以考虑二分,至于代码,\(\color{red}{PigeonGuGuGu}\)。
设平台最左边覆盖的点为\(e\),最右边覆盖的点为\(b\),不难发现\(e >= b\),这时候满足了__two-pointer__(尺取)的性质,我们可以设两个数组\(l, r\),\(l\)表示从\(point[1, t]\)能够覆盖的最多的点,\(r\)表示从\(point[t, n)\)能够覆盖的最多的点,求出\(l, r\)之后,枚举\(t\)来求出答案。
Code:
/*
ID: Loxilante
Time: 2020/09/05
Prog: CF1409E
Lang: cpp
*/
#ifdef ONLINE_JUDGE
#pragma GCC optimize("O3")
#endif
#include <bits/extc++.h>
#define rep(i, l, r) for(int i = l; i < r; i++)
#define hrp(i, l, r) for(int i = l; i <= r; i++)
#define rev(i, r, l) for(int i = r; i >= l; i--)
#define ms(n, t) memset(n, t, sizeof(n))
#define pb push_back
#define int ll
#ifndef JOEON
#define D(...) 97
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
template<typename tn = int> inline tn next(void) { tn k; cin>>k; return k; }
const int U = 2e5+50;
int w[U], l[U], r[U];
signed main(void)
{
#ifdef JOEON
// freopen("C:\\Users\\Joeon\\Desktop\\IN.txt", "r", stdin);
// freopen("C:\\Users\\Joeon\\Desktop\\OUT.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
int T = next();
while(T--)
{
int n, t;
cin>>n>>t;
rep(i, 0, n) cin>>w[i];
rep(i, 0, n) next();
sort(w, w+n);
if (w[n-1]-w[0] <= t*2) { cout<<n<<endl; continue; }
int pos = 0;
rep(i, 0, n)
{
while(w[pos]-w[i] <= t && pos < n) pos++;
r[i] = pos-i;
}
rev(i, n-2, 0) r[i] = max(r[i+1], r[i]);
pos = n-1;
rev(i, n-1, 0)
{
while(w[i]-w[pos] <= t && pos >= 0) pos--;
l[i] = i-pos;
}
rep(i, 1, n) l[i] = max(l[i-1], l[i]);
int ans = -1<<30;
rep(i, 0, n) ans = max(ans, l[i]+r[i+1]);
cout<<ans<<endl;
}
return 0;
}
F:
给你一个长为\(n\)的字符串\(a\)和长为\(2\)的字符串\(b\)和\(k\),你有\(k\)次机会修改\(a\)中元素,\(a\)中有\(ans\)个子序列为\(b\),求\(ans\)最大值。
一道明显的3维 dp ,dp方程有亿点长(
在字符串\(a\)中,\(ans\)实际是每个\(b\)之前\(a\)的个数之和。
显而易见,修改\(a\)中字符只会修改成\(b[0]\)或\(b[1]\),综上,我们可以设置dp状态为\(dp(i,j,k)\),i代表当前下标,\(j\)代表已使用\(s\)次修改机会,\(k\)代表在\(i\)及之前出现\(b[0]\)的次数,那我们可以对dp方程进行分类讨论 :
- 不修改字符,这时我们分类讨论:
- 当前字符为\(b[0]\),即\(dp(i, j, k) = dp(i-1, j, k-1)\)。
- 当前字符为\(b[1]\),即\(dp(i, j, k) = dp(i-1, j, k) + k\)。
- 既不是\(b[0]\)也不是\(b[1]\),即\(dp(i, j, k) = dp(i-1, j, k)\)。
- 修改字符,这时我们又要分类讨论:
- 当前字符不为\(b[1]\),那我们可以把它修改为\(b[1]\),即\(dp(i, j, k) = dp(i, j-1, k-1)\)。
- 当前字符不为\(b[0]\),那我们可以把它修改为\(b[0]\),即\(dp(i, j, k) = dp(i, j-1, k)+k\)。
还有一个小特判,当\(b[0] == b[1]\)的时候,修改\(a\)中非\(b[0]\)的哪一个字符都可以,令\(p=max\{k+cnt, n\}\),则答案为\(C _p ^2\),可化为\(p(p-1)/2\),读者自证不难。
Code:
/*
ID: Loxilante
Time: 2020/09/06
Prog: CF1409F
Lang: cpp
*/
#ifdef ONLINE_JUDGE
#pragma GCC optimize("O3")
#endif
#include <bits/extc++.h>
#define rep(i, l, r) for(int i = l; i < r; i++)
#define hrp(i, l, r) for(int i = l; i <= r; i++)
#define rev(i, r, l) for(int i = r; i >= l; i--)
#define ms(n, t) memset(n, t, sizeof(n))
#define pb push_back
#define int ll
#ifndef JOEON
#define D(...) 97
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
template<typename tn = int> inline tn next(void) { tn k; cin>>k; return k; }
const int U = 2e2+50;
int dp[U][U][U];
signed main(void)
{
#ifdef JOEON
// freopen("C:\\Users\\Joeon\\Desktop\\IN.txt", "r", stdin);
// freopen("C:\\Users\\Joeon\\Desktop\\OUT.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
int n, s, ans = -1<<30;
cin>>n>>s;
string a, b;
cin>>a>>b;
if (b[0] == b[1])
{
int cnt = s;
rep(i, 0, n) cnt += a[i] == b[0];
cnt = min(cnt, n);
cout<<cnt*(cnt-1)/2<<endl;
return 0;
}
ms(dp, -2);
hrp(j, 0, s) dp[0][j][0] = 0;
auto chkmax = [=](auto& a, auto b)
{
if (b > a) a = b;
};
rep(i, 0, n) hrp(j, 0, s) rep(k, 0, n)
{
#define now dp[i+1][j][k]
now = dp[i][j][k];
if (a[i] == b[0] && k) chkmax(now, dp[i][j][k-1]);
else if (j && k) chkmax(now, dp[i][j-1][k-1]);
if (a[i] == b[1]) chkmax(now, dp[i][j][k]+k);
else if (j) chkmax(now, dp[i][j-1][k]+k);
#undef now
}
rep(k, 0, n) chkmax(ans, dp[n][s][k]);
cout<<ans<<endl;
return 0;
}
完结撒花~~~
唯一一篇AK的的题解