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}\)

  1. 不要用字符串来处理\(p\),我就是这样然后被虐了

  2. 这道题\(p\) \(\color{orange}{long long}\)装不下,所以我们可以用\(\color{orange}{unsigned long long}\)

  3. 要特判\(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方程进行分类讨论 :

  1. 不修改字符,这时我们分类讨论:
    1. 当前字符为\(b[0]\),即\(dp(i, j, k) = dp(i-1, j, k-1)\)
    2. 当前字符为\(b[1]\),即\(dp(i, j, k) = dp(i-1, j, k) + k\)
    3. 既不是\(b[0]\)也不是\(b[1]\),即\(dp(i, j, k) = dp(i-1, j, k)\)
  2. 修改字符,这时我们又要分类讨论:
    1. 当前字符不为\(b[1]\),那我们可以把它修改为\(b[1]\),即\(dp(i, j, k) = dp(i, j-1, k-1)\)
    2. 当前字符不为\(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的的题解

posted @ 2020-09-06 20:51  Loxilante  阅读(232)  评论(0编辑  收藏  举报