Educational Codeforces Round 131 (Rated for Div. 2)

题目连接

C

核心思路

这个题目乍一看是一个模拟题其实这是一个可以使用二分的题目,因为这其实只需要我们找到答案就好了。

那么二分怎么去check呢,我们可以计算出来每一位工人在x小时可以完成的任务量。

首先我们可以搞出来某一个工人擅长哪几种任务,对于这几种任务它可以一个小时就完成一个,而对于他不擅长的则需要两个小时才可以完成一个。

于是我们只需要看他们是否大于我们规定的任务量就好了。

// Problem: C. Schedule Management
// Contest: Codeforces - Educational Codeforces Round 131 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1701/problem/C
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define NO {puts("NO") ; return ;}
#define YES {puts("YES") ; return ;}
#define endl "\n"
#define int long long 
const int INF = 0x3f3f3f3f;
const int N=2e5+10;
int cnt[N];

int n,m;
int check(int x)
{
	int sum=0;
	for(int i=1;i<=n;i++)
	{
		if(cnt[i]>=x)
		sum+=x;
		else
		sum+=cnt[i]+(x-cnt[i])/2;
	}
	return sum>=m;
	
	
}

void solve()
{
	cin>>n>>m;
	memset(cnt,0,sizeof cnt);
	for(int i=1;i<=m;i++)
	{
		int x;
		cin>>x;
		cnt[x]++;
	}
	int l=1,r=2*m;
	while(l<r)
	{
		int mid=l+r>>1;
		if(check(mid))
		r=mid;
		else
		l=mid+1;
	}
	cout<<l<<endl;
	
	
	
}



signed main()
{
int t;
cin>>t;
while(t--)
{
	solve();
}
}

D

核心思路

其实我们首先应该需要推导出来的是\(a_i\)的表达式,因为\(b_i=\lfloor{i/a_i}\rfloor\).所以\(a_i*b_i\leq i < a_i*(b_i+1)\).

所以我们可以得出来\(\lfloor{i/(b_i+1)}\rfloor+1 \leq a_i \leq \frac{i}{b_i}\).

所以我们可以得出来每一个位置的一个取值范围,然后我们把每一个数可以填入的左边界先预处理出来,比如可以填入1这个数组的位置一定是\([1,2],[1,3]...\).然后我们贪心这个位置的右边界,这个是什么意思呢,也就是这个位置所对应的最小有边界,也就是在上面那几个区间里面就选择\([1,2]\)这个区间的位置来填入我们的数字1。

这样做是为了不影响后面的填数。

// Problem: D. Permutation Restoration
// Contest: Codeforces - Educational Codeforces Round 131 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1701/problem/D
// Memory Limit: 256 MB
// Time Limit: 4000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define NO {puts("NO") ; return ;}
#define YES {puts("YES") ; return ;}
#define endl "\n"
#define int long long 
const int INF = 0x3f3f3f3f;

const int N=5e5+10;
int l[N],r[N];
int a[N],b[N];
struct Node{
	int x,id;
	bool operator < (const Node& t) const {
		return x>t.x;
	}
};
priority_queue<Node> q;
int n;
vector<int> c[N];
void solve()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>b[i];
		if(!b[i])
		{
			l[i]=i+1;
			r[i]=n;
		}
		else
		{
			l[i]=((i/(b[i]+1))+1);
		r[i]=i/b[i];
		}
		c[l[i]].push_back(i);
	}
	// for(int i=1;i<=n;i++)
	// cout<<l[i]<<" "<<r[i]<<endl;
	while(!q.empty())
	q.pop();
	for(int i=1;i<=n;i++)
	{
		for(int x:c[i])
		q.push((Node){r[x],x});
		Node temp=q.top();
	//	cout<<temp.x<<" "<<temp.id<<endl;
		q.pop();
		a[temp.id]=i;
			}
	for(int i=1;i<=n;i++)
	{
		cout<<a[i]<<" ";
	c[i].clear();
	}
	cout<<endl;
	
}


signed main()
{
int t;
cin>>t;
while(t--)
{
	solve();
}
}

E

核心思路

这个题目根据数据范围可以看出来这是一个dp的题目,那么怎么设计状态表示呢,我们可以通过模拟小规模样例。

首先我们知道肯定要有状态表示当前光标移动到了a串的什么位置和b串的什么位置。还有就是需要注意我们的光标是可以跳跃的,所以我们可以把我们的整个字符串分为前中后三个位置,方便我们的状态转移。

集合定义

\(f[i][j][0/1/2]表示的是当前处理到了a的第i个字符和b的第j个字符,当前光标在前中后部分的最少移动次数\)

集合划分

  1. 我们知道任意时刻我们都是可以删除a中的字符的,但是要注意如果我们在光标在前面的部分,我们需要花费代价2因为先要往右移动才可以删除字符。
  2. 如果\(a_i=b_j\).如果如果在前部分那么直接往右移动匹配长度加1,如果是后面就需要往左移动匹配长度加1.如果是在中间,那么就由前面的状态转移过来。
  3. 这里还有一个需要注意的是,任意时刻光标都可以从前半部分转入中/后部分,或者从中部分转入后部分。

最后还需要按下home操作归还原理啊。操作3我不是很理解,估计是模拟样例退出来的。

/*

p_b_p_b txdy
AThousandMoon txdy
AThousandSuns txdy
hxy txdy

*/

#include <bits/stdc++.h>
#define pb push_back
#define fst first
#define scd second

using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;

const int maxn = 5050;
const int inf = 0x3f3f3f3f;

int n, m, f[2][maxn][3];
char s[maxn], t[maxn];

void solve() {
	scanf("%d%d%s%s", &n, &m, s + 1, t + 1);
	int j = 0;
	for (int i = 1; i <= n; ++i) {
		if (j < m && t[j + 1] == s[i]) {
			++j;
		}
	}
	if (j < m) {
		puts("-1");
		return;
	}
	int pl = m;
	for (int i = 1; i <= m; ++i) {//这里是指直接删除后面的部分。
		if (s[i] != t[i]) {
			pl = i - 1;
			break;
		}
	}
	int cur = 0;
	for (int i = 0; i <= m; ++i) {
		f[0][i][0] = f[0][i][1] = f[0][i][2] = inf;
	}
	f[0][0][0] = f[0][0][1] = f[0][0][2] = 0;
	for (int i = 1; i <= n; ++i) {
		cur ^= 1;
		for (int j = 0; j <= m; ++j) {
			f[cur][j][0] = f[cur][j][1] = f[cur][j][2] = inf;
		}
		for (int j = 0; j <= m; ++j) {
			f[cur][j][0] = min(f[cur][j][0], f[cur ^ 1][j][0] + 2);
			f[cur][j][2] = min(f[cur][j][2], f[cur ^ 1][j][2] + 1);
			if (j && s[i] == t[j]) {
				f[cur][j][0] = min(f[cur][j][0], f[cur ^ 1][j - 1][0] + 1);
				f[cur][j][1] = min(f[cur][j][1], f[cur ^ 1][j - 1][1]);
				f[cur][j][2] = min(f[cur][j][2], f[cur ^ 1][j - 1][2] + 1);
			}
		}
		for (int j = 0; j <= m; ++j) {
			f[cur][j][1] = min(f[cur][j][1], f[cur][j][0]);
			f[cur][j][2] = min(f[cur][j][2], f[cur][j][1]);
		}
	}
	printf("%d\n", min(n - pl, f[cur][m][2] + 1));
}

int main() {
	int T = 1;
	scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}
posted @ 2023-04-12 21:22  努力的德华  阅读(29)  评论(0)    收藏  举报