2024暑假集训测试22

前言

今天题好难啊,大多数人 T2、T4 改不动都不改了,下午 miaomiao 进来和我们说模拟赛改不动的题可以不改。

部分分给的也很少。

T1 Mortis

\(O(n)\) 桶排序,知道每个数最后应该去哪,那么对于需要交换的只有三种情况:

  1. 二者错排,交换一次。
  2. 三者错排,交换两次。
  3. 四者错排,交换三次。

当然这几种情况优先处理第一种,其次第二种,最后第三种,由此处理即可,最后总的复杂度是线性的。

点击查看代码
#include<bits/stdc++.h>
#define ll long long 
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=2e5+10;
template<typename Tp> inline void read(Tp&x)
{
	x=0;register bool z=true;
	register char c=getchar();
	for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
	for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	x=(z?x:~x+1);
}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
template<typename Tp> inline void wt(Tp x)
{if(x>9)wt(x/10);putchar((x%10)+'0');}
template<typename Tp> inline void write(Tp x)
{if(x<0)putchar('-'),x=~x+1;wt(x);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar(' ');write(y...);}
int n,a[N],sum[5],b[N],cnt[5][5],ans,tot;
signed main()
{
	read(n);
	for(int i=1;i<=n;i++) 
	{
		read(a[i]);
		sum[a[i]]++;
	}
	for(int i=1,pre=0;i<=4;i++)
	{
		for(int j=1;j<=sum[i];j++)
			b[pre+j]=i;
		pre+=sum[i];
	}
	for(int i=1;i<=n;i++)
		if(a[i]!=b[i])
		{
			tot++;
			cnt[a[i]][b[i]]++;
		}
	for(int i=1;i<=4;i++)
		for(int j=1;j<=4;j++)
			if(i!=j)
			{
				int s=min(cnt[i][j],cnt[j][i]);
				ans+=s,tot-=s<<1;
				cnt[i][j]-=s,cnt[j][i]-=s;
			}
	for(int i=1;i<=4;i++)
		for(int j=1;j<=4;j++)
			if(i!=j) for(int k=1;k<=4;k++)
				if(i!=k&&j!=k)
				{
					int s=min({cnt[i][j],cnt[j][k],cnt[k][i]});
					ans+=s<<1,tot-=(s<<1)+s;
					cnt[i][j]-=s,cnt[j][k]-=s,cnt[k][i]-=s;
				}
	write(ans+tot/4*3);
}

T2 生活在hzoi上

不会。

T3 嘉然今天吃什么

  • 原题:P8511 [Ynoi Easy Round 2021] TEST_68

  • 部分分 \(10pts\):每个区间都跑一次 \(01trie\),复杂度 \(O(n^2\log v)\)

  • 正解:

    求出 \(dfs\) 序,可以转化为序列问题,点 \(x\) 对应区间 \([1,in_x),(out_x,n)\)

    发现对于大多数的区间都是全局最大值,可以处理出达成这个答案的是哪两个点,这是 \(01trie\) 板子。

    然后对于整棵树上,只有 \(1\to lca,lca\to u,lca\to v\) 这几段路径是不能使用全局最大值的,又发现这是一条链,链是好处理的,因为 \(fa_x\) 对应区间一定包含在 \(x\) 对应区间内,用两个指针维护就行了。

    点击查看代码
    #include<bits/stdc++.h>
    #define ll long long 
    #define endl '\n'
    #define sort stable_sort
    using namespace std;
    const int N=5e5+10,M=3e7+10;
    template<typename Tp> inline void read(Tp&x)
    {
        x=0;register bool z=true;
        register char c=getchar();
        for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
        for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
        x=(z?x:~x+1);
    }
    template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
    template<typename Tp> inline void wt(Tp x)
    {if(x>9)wt(x/10);putchar((x%10)+'0');}
    template<typename Tp> inline void write(Tp x)
    {if(x<0)putchar('-'),x=~x+1;wt(x);}
    template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar(' ');write(y...);}
    int n,tot,u,v,lca,top1,top2,fa[N],in[N],out[N],dep[N];
    ll mx_a,maxx,mx,a[N],b[N],ans[N];
    bool vis[N];
    vector<int>e[N];
    struct trie
    {
        int tot,t[M][2],pos[M];
        void insert(int id)
        {
            ll x=a[id]; int p=0;
            for(int i=__lg(mx_a),c;i>=0;i--)
            {
                c=(x>>i)&1;
                if(!t[p][c]) t[p][c]=++tot;
                p=t[p][c];
            }
            pos[p]=id;
        }
        int ask(ll x)
        {
            int p=0;
            for(int i=__lg(mx_a),c;i>=0;i--)
            {
                c=(x>>i)&1;
                if(t[p][!c]) p=t[p][!c];
                else p=t[p][c];
            }
            return pos[p];
        }
        void clear() 
        {
            for(int i=0;i<=tot;i++) 
                t[i][0]=t[i][1]=pos[i]=0;
            tot=0;
        }
    }T;
    void dfs(int x,int dis)
    {
        in[x]=++tot,dep[x]=dis;
        for(int y:e[x]) dfs(y,dis+1);
        out[x]=tot;
    }
    int lca_(int x,int y)
    {
        if(dep[x]<dep[y]) swap(x,y);
        for(;dep[x]!=dep[y];x=fa[x]) vis[x]=1;
        for(;x!=y;x=fa[x],y=fa[y]) vis[x]=vis[y]=1;
        return x;
    }
    void dfs(int x,int goal,int l,int r)
    {
        if(!x) return ;
        for(int s;l<=in[x]-1;l++) 
        {
            T.insert(l);
            s=T.ask(a[l]);
            mx=max(mx,a[l]^a[s]);
        }
        for(int s;r>=out[x]+1;r--) 
        {
            T.insert(r);
            s=T.ask(a[r]);
            mx=max(mx,a[r]^a[s]);
        }
        ans[x]=mx;
        if(x==goal) return ; 
        for(int y:e[x]) if(vis[y]) 
        {
            dfs(y,goal,l,r);
            break;
        }
    }
    signed main()
    {
        read(n);
        for(int i=2;i<=n;i++) 
        {
            read(fa[i]);
            e[fa[i]].push_back(i);
        }
        for(int i=1;i<=n;i++) 
        {
            read(a[i]);
            mx_a=max(mx_a,a[i]);
        }
        for(int i=1,j;i<=n;i++) 
        {
            T.insert(i);
            j=T.ask(a[i]);
            if((a[i]^a[j])>maxx)
            {
                maxx=a[i]^a[j];
                u=i,v=j;
            }
        }
        dfs(1,1);
        memcpy(b,a,sizeof(a));
        for(int i=1;i<=n;i++) a[in[i]]=b[i];
        lca=lca_(u,v); 
        for(int i=lca;i;i=fa[i]) vis[i]=1;
        for(int i=u;i!=lca;i=fa[i]) top1=i;
        for(int i=v;i!=lca;i=fa[i]) top2=i;
        T.clear(); mx=0; dfs(1,lca,1,n);
        T.clear(); mx=0; dfs(top1,u,1,n);
        T.clear(); mx=0; dfs(top2,v,1,n);
        for(int i=1;i<=n;i++) write(vis[i]?ans[i]:maxx),puts("");
    }
    

T4 APJifengc

不会。

总结

不知道说点什么,只是好想秦皇岛啊。

附录

题目背景比较魔怔,看题目名称也能看出来。

posted @ 2024-08-11 21:00  卡布叻_周深  阅读(37)  评论(1)    收藏  举报