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<<"
"[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的的题解