Educational Codeforces Round 76 (Rated for Div. 2) E. The Contest


Educational Codeforces Round 76 (Rated for Div. 2) E. The Contest(dp+線段樹)

題目鏈接

題意:

給定3個人互不相同的多個數字,可以把數字移動給別人,問最少移動幾次后可以使第一個人的數字為1~m1,第二個人m1~m2,第三個人m2~n(可以沒有數字)

題解:

設c[1][i]為第一個人m1為i時需要移動的次數,c[3][i]為m2為i是第三個人需要操作的次數,當其他兩個人數字合法時,第二個人的數字也會合法.枚舉第一個人的每個i,查詢m2為(i+1~n+1)的最小操作次數,ans = min{c[1][i]+min(c[3]k)} 查詢操作可用線段樹維護

代碼:

#include <bits/stdc++.h>
using namespace std;
const int N = 250000;
int t[4*N],a[5][N],b[5][N],c[5][N];
void build(int x,int l,int r)
{
	if (l == r) 
	{
		t[x] = c[3][l];
		return;
	}
	int mid = (l + r) >>1;
	build(x<<1,l,mid);
	build(x<<1|1,mid+1,r);
	t[x] = min(t[x<<1] , t[x<<1|1]);
}
int query(int x,int l,int r,int ll,int rr)
{
	if (ll <= l && r <= rr) return t[x];
	int mid = (l + r) >> 1;
	int ans = 1<<30;
	if (ll <= mid) ans = min(ans,query(x<<1,l,mid,ll,rr));
	if (rr > mid ) ans = min(ans,query(x<<1|1,mid+1,r,ll,rr));
	return ans;
}
int main()
{
	int k1,k2,k3;
	cin >> k1 >> k2 >> k3;
	int n = k1+k2+k3;
	memset(b,0,sizeof(b));
	memset(c,0,sizeof(c));
	for (int i = 1; i <= k1; i++) 
	{
		cin >> a[1][i];
		b[1][a[1][i]] = 1;
	}
	for (int i = 1; i <= k2; i++) cin >> a[2][i];
	for (int i = 1; i <= k3; i++)
	{
		cin >> a[3][i];
		b[3][a[3][i]] = 1;
	}
	c[1][0] = k1;
	for (int i = 1; i <= n; i++)
	{
		b[1][i] = b[1][i-1]+b[1][i]; //記錄第一個人前i個數中擁有幾個 
		c[1][i] = i - b[1][i] + k1 - b[1][i];//i-b[1][i]為需要移動到第一個人的操作數,k1-b[1][i]為第一個人把數移動出去的操作數
	}
	c[3][n+1] = k3;
	for (int i = n; i; i--)
	{
		b[3][i] = b[3][i+1] + b[3][i];
		c[3][i] = n-i+1-b[3][i] +k3 - b[3][i]-(k1-b[1][i-1]); //如果是第一個人可以移動到第三個人的數會重復需要減掉
	}
	for (int i = 1; i < n; i++)
	 c[1][i] -= k3-b[3][i+1];//第三個人可以移動到第一個人的數
	build(1,0,n+1);
	int ans = c[1][n];
	for (int i = 0; i < n; i++)
	{
		ans = min(ans, c[1][i] + query(1,0,n,i+1,n+1));
	}
	cout << ans << endl;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM