多校A层冲刺NOIP2024模拟赛06
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;
}
/*
*/