1 条题解

  • 0
    @ 2026-9-2 0:36:37

    嗯,这破题,真的很让人讨厌。

    首先,观察数据范围,发现 k k 只有两种情况,直接入手。

    k=2n2 k=2n-2 时,给前 n1 n-1 个栈每个分配两种颜色,这样每次遇到需要消除的情况时只需要在空栈中操作,必然能够完成。

    k=2n1 k=2n-1 时,发现之前的做法不能成立,倘若极限情况下前 n1 n-1 个栈堆满后又来一种新的颜色,此时就无法放置,所以我们做出一些变化。

    记录 nxt nxt 数组,记录一张牌后面第一张与它匹配的牌的位置,特别地,对于被用来匹配的牌不记录。

    假如前 n1 n-1 个栈未放满或放满后仍然未出现多余的颜色,此时直接按照上文所述的做即可,接下来讨论最麻烦的情况,即放满后出现了多余的颜色。

    我们考虑前 n1 n-1 个栈中栈顶和栈底元素 nxt nxt 的关系。倘若我们发现存在一个栈,它的栈顶元素 nxt nxt 值大于栈底元素 nxt nxt 值,那么可以将新元素放在该栈上,因为在消除栈顶元素前一定会先消除栈底元素。倘若不存在,便说明在所有栈底元素中 nxt nxt 最小的元素消除前,消除操作一定都是在栈顶进行,那么可以将新元素放入原本的空栈,等到消除出一个新的空栈,而上文的限制则保证了操作的合法性。

    于是记录出空栈位置 Free Free ,及时更新即可。

    感觉写的还行吧:

    #include<iostream>
    #include<iomanip>
    #include<cmath>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    using namespace std;
    #define md(a) a=(a%mod+mod)%mod
    #define file(a) freopen(#a".in","r",stdin);freopen(#a".out","w",stdout)
    const int Ns=305,Ncd=4000005,Ncol=705;
    int T,Now;
    int n,m,Num,col[Ncd];
    int nxt[Ncd],las[Ncol];
    int Free,st[Ns][2];
    struct Do{int op,x,y;};
    vector<Do>Res;
    void Clear()
    {
    	Res.clear();
    	for(int i=1;i<=n;i++)st[i][0]=st[i][1]=0;
    	for(int i=1;i<=m;i++)nxt[i]=0;
    	for(int i=1;i<=Num;i++)las[i]=0;
    }
    void Up(int x){Res.push_back({1,x,0});}
    void Down(int x,int y){Res.push_back({1,y,0}),Res.push_back({2,min(x,y),max(x,y)});}
    pair<int,int>Fcol(int c){for(int i=1;i<=n;i++){if(col[st[i][0]]==c)return {i,0};if(col[st[i][1]]==c)return {i,1};}}
    int Fsta(){for(int i=1;i<=n;i++)if(i!=Free&&st[i][0]==0)return i;return -1;}
    int Fuld(){for(int i=1;i<=n;i++)if(i!=Free&&nxt[st[i][0]]>nxt[st[i][1]])return i;return -1;}
    int Fmin(){pair<int,int>ans={m+1,0};for(int i=1;i<=n;i++)if(i!=Free)ans=min(ans,{nxt[st[i][1]],i});return ans.second;}
    void Use_Normal(int i)
    {
    	if(nxt[i]==0)
    	{
    		pair<int,int>Pos=Fcol(col[i]);
    		int x=Pos.first,y=Pos.second;
    		if(y==0)Up(x),st[x][0]=0;
    		else Down(x,Free),st[x][1]=st[x][0],st[x][0]=0;
    	}
    	else
    	{
    		int Pos=Fsta();
    		Up(Pos),st[Pos][(st[Pos][1]==0)]=i;
    	}
    }
    int Use_Free(int i)
    {
    	int Pos=Fuld();
    	if(Pos!=-1)
    	{
    		Up(Pos);int mn=min(nxt[st[Pos][1]],nxt[i]);
    		for(int j=i+1;j<=mn-1;j++)Use_Normal(j);
    		if(nxt[st[Pos][1]]<nxt[i])Down(Pos,Free),st[Pos][1]=st[Pos][0],st[Pos][0]=i;
    		else Up(Pos);
    		return mn+1;
    	}
    	else
    	{
    		Pos=Fmin(),Up(Free);
    		int mn=min(nxt[st[Pos][1]],nxt[i]);
    		if(nxt[st[Pos][1]]<nxt[i])st[Free][1]=i,Free=Pos;
    		for(int j=i+1;j<=mn-1;j++)Use_Normal(j);
    		if(nxt[st[Pos][1]]<nxt[i])Up(Pos),st[Pos][1]=0;
    		else Up(Free),st[Free][1]=0;
    		return mn+1;
    	}
    }
    void Start()
    {
    	if(n==1){for(int i=1;i<=m;i++)Up(1);return ;}
    	Free=n;
    	for(int i=1;i<=m;)
    	{
    		if(nxt[i]==0)Use_Normal(i),i++;
    		else
    		{
    			int Pos=Fsta();
    			if(Pos!=-1)Up(Pos),st[Pos][(st[Pos][1]==0)]=i,i++;
    			else i=Use_Free(i);
    		}
    	}
    }
    void Play_Game()
    {
    	scanf("%d%d%d",&n,&m,&Num);
    	for(int i=1;i<=m;i++)scanf("%d",&col[i]);
    	for(int i=1;i<=m;i++)
    	{
    		if(las[col[i]])nxt[las[col[i]]]=i,las[col[i]]=0;
    		else las[col[i]]=i;
    	}
    	Start();
    	cout<<Res.size()<<endl;
    	for(Do x:Res)
    	{
    		if(x.op==1)printf("1 %d\n",x.x);
    		else printf("2 %d %d\n",x.x,x.y);
    	}
    	Clear();
    }
    signed main()
    {
    	scanf("%d",&T);
    	while(T--)Play_Game();
    	return 0;
    }
    
    • 1

    信息

    ID
    1975
    时间
    1000ms
    内存
    512MiB
    难度
    10
    标签
    递交数
    11
    已通过
    1
    上传者