多校A層衝刺NOIP2024模擬賽06

_君の名は發表於2024-10-13

A. 小 Z 的手套(gloves)

明現的二分,我們先排序,假定 \(a\) 陣列個數少,我們就對每一個 \(a_i\) 找一個 \(b_i\) 使其差不超過二分的值,然後

貪心來講,肯定找相差最大的那組但差不超過二分值的那個數最優,且先找比他小的那組(因為排過序了),然後套個

\(multiset\) 就過了,雖然 \(n{log_n}^2\)

點選檢視程式碼
#include<bits/stdc++.h> 
const int maxn=1e5+10;
using namespace std;
int n,m,a[maxn],b[maxn],ans;
multiset<int>t;
multiset<int>::iterator pos1,pos2;

bool check(int x)
{
	t.clear();
	for(int i=1;i<=m;i++) t.insert(b[i]);
	for(int i=1;i<=n;i++)
	{
		pos1=t.lower_bound(a[i]-x);
//		cout<<a[i]<<" "<<*pos1<<endl;
		if(pos1!=t.end()&&abs(a[i]-*pos1)<=x)
		{
			t.erase(t.find(*pos1));
		}
		else
		{
			pos1=t.upper_bound(x-a[i]);
			if(pos1!=t.end()&&abs(*pos1-a[i])<=x)
			{
				t.erase(t.find(*pos1));
			}
			else return 0;
		}
	}
	return 1;
}

int main()
{
	freopen("gloves.in","r",stdin);
	freopen("gloves.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=m;i++) cin>>b[i];
	sort(a+1,a+1+n),sort(b+1,b+1+m);
	if(n>m)
	{
		for(int i=1;i<=n;i++) swap(a[i],b[i]);
		swap(n,m);
	}
	int l=0,r=1e9;
	while(l<=r)
	{
		int mid=l+r>>1;
		if(check(mid))r=mid-1,ans=mid;
		else l=mid+1;
	}
	cout<<ans;

	return 0;
}
/*

*/

B. 小 Z 的字串(string)

\(dp\) ,設 \(f_{i,j,k,s}\) 表示前 \(i\) 位,\(j\) 個0,\(k\) 個1,第 \(i\) 位換完後是 \(s\) 的最小代價,因為換兩個相同的數是不優的,所以相同的數的

相對位置相同,然後轉移就完了

點選檢視程式碼
#include<bits/stdc++.h>
#define pr pair<int,int> 
const int maxn=410;
using namespace std;
int ans,n,cnt[3],f[maxn][maxn>>1][maxn>>1][3],pos[3][maxn];
string s;

int main()
{
	freopen("string.in","r",stdin);
	freopen("string.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>s;n=s.size();s=" "+s;
	for(int i=1;i<=n;i++) pos[s[i]-'0'][++cnt[s[i]-'0']]=i;
	if(cnt[0]>(n+1)/2||cnt[1]>(n+1)/2||cnt[2]>(n+1)/2)
	{
		cout<<-1;
		return 0;
	}
	memset(f,0x7f,sizeof f);
	f[0][0][0][0]=f[0][0][0][1]=f[0][0][0][2]=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<=i&&j<=cnt[0];j++)
		{
			for(int k=0;k+j<=i&&k<=cnt[1];k++)
			{
//				cout<<i<<" "<<j<<" "<<k<<endl;
				int p=i-j-k;
				if(j) f[i][j][k][0]=min(f[i][j][k][0],min(f[i-1][j-1][k][1],f[i-1][j-1][k][2])+abs(i-pos[0][j]));
				if(k) f[i][j][k][1]=min(f[i][j][k][1],min(f[i-1][j][k-1][0],f[i-1][j][k-1][2])+abs(i-pos[1][k]));
				if(p) f[i][j][k][2]=min(f[i][j][k][2],min(f[i-1][j][k][0],f[i-1][j][k][1])+abs(i-pos[2][p]));
			}
		}
	}
	cout<<min(f[n][cnt[0]][cnt[1]][0],min(f[n][cnt[0]][cnt[1]][1],f[n][cnt[0]][cnt[1]][2]))/2;
	
	return 0;
}
/*

*/

C. 一個真實的故事(truth)

發現一個區間只有最左邊的 \(1-k\) ,最右邊的 \(1-k\) ,區間本身最小的 \(1-k\) 對答案有貢獻,用線段數維護最左/右的

\(1-k\) 的位置,合併時把中間 \(2*k\) 個數取出來排序,雙指標更新答案

點選檢視程式碼
#include<bits/stdc++.h> 
#define lid id<<1
#define rid id<<1|1
const int maxn=5e4+10;
using namespace std;
int n,k,q,a[maxn];
struct lsx
{
	int l,r,lk[55],rk[55],ans;
}m[maxn<<2];

void up(int id)
{
	for(register int i=1;i<=k;i++)
	{
		m[lid].lk[i]?m[id].lk[i]=m[lid].lk[i]:m[id].lk[i]=m[rid].lk[i];
		m[rid].rk[i]?m[id].rk[i]=m[rid].rk[i]:m[id].rk[i]=m[lid].rk[i];
	}
	pair<int,int> s[110];
	int op=0;
	for(register int i=1;i<=k;i++)
	{
		(m[lid].rk[i]>0)&&(s[++op]={m[lid].rk[i],i},0);	
		(m[rid].rk[i]>0)&&(s[++op]={m[rid].lk[i],i},0);
	}
	sort(s+1,s+1+op);
	int sum=0,cnt[55]={0},l=1,r=1;
	while(l<=op)
	{
		while(r<=op)
		{
			int x=s[r].first,y=s[r].second; 
			if(!cnt[y])sum++;
			cnt[y]++;
			if(sum==k)
			{
				if(!m[id].ans) m[id].ans=s[r].first-s[l].first+1;
				else m[id].ans=min(m[id].ans,s[r].first-s[l].first+1);
				cnt[y]--;
				if(!cnt[y])sum--;
				break;
			}
			r++;
		}
		cnt[s[l].second]--;
		if(!cnt[s[l].second])sum--;
		l++;
	}
	if(m[lid].ans) m[id].ans=min((m[id].ans==0?1000000000:m[id].ans),m[lid].ans);
	if(m[rid].ans) m[id].ans=min((m[id].ans==0?1000000000:m[id].ans),m[rid].ans);
}

inline void build(int id,int l,int r)
{
	m[id].l=l,m[id].r=r;
	if(l==r)
	{
		m[id].lk[a[l]]=m[id].rk[a[l]]=l;
		return; 
	}
	int mid=(l+r)>>1;
	build(lid,l,mid);
	build(rid,mid+1,r);
	up(id);
}

inline void update(int id,int x,int y)
{
	int l=m[id].l,r=m[id].r;m[id].ans=0;
	if(l==r)
	{
		m[id].lk[a[l]]=m[id].rk[a[l]]=0;
		m[id].lk[y]=m[id].rk[y]=l;
		return; 
	}
	int mid=(l+r)>>1;
	x<=mid?update(lid,x,y):update(rid,x,y);
	up(id);
}

int main()
{
	freopen("truth.in","r",stdin);
	freopen("truth.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>k>>q;
	for(register int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	build(1,1,n);
	while(q--)
	{
		int op,x,y;
		cin>>op;
		if(op==1)
		{
			cin>>x>>y;
			update(1,x,y);
			a[x]=y;
		}
		else
		{
			if(!m[1].ans)
			{
				cout<<-1<<'\n';
			}
			else cout<<m[1].ans<<'\n';
		}
	}

	return 0;
}
/*

*/

stars

image

相關文章