专栏文章
题解:P10191 [USACO24FEB] Test Tubes S
P10191题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @min23dow
- 此快照首次捕获于
- 2025/12/01 19:18 3 个月前
- 此快照最后确认于
- 2025/12/01 19:18 3 个月前
题解:P10191 [USACO24FEB] Test Tubes S
前言
小小思维题。
题意简述
你有三个栈,每次可以将一个栈顶端所有颜色相同的数移动到另外一个栈顶。
最开始只有第一个和第二个栈有数,并且只有两种。求让第一个栈和第二个栈中的数都相同的最小操作数,并给出操作方法(并且需要保证第三个栈中没有数)。
最开始只有第一个和第二个栈有数,并且只有两种。求让第一个栈和第二个栈中的数都相同的最小操作数,并给出操作方法(并且需要保证第三个栈中没有数)。
思路
这里令三个栈分别为 其 分别为 。
注意到每次移动只能将连续的相同颜色的数移动,那么我们就把连续相同颜色的数捆在一起。这样可以方便我们的操作。
那么如果我们将某个栈顶移动到的另外一个栈顶,且它们颜色相同,可以视作弹出了前者的栈顶。
于是有个重要结论, 中只可能有 1 个数,且永远不会变。
证明如下:
可能不太严谨。首先如果 的栈顶相同时,我们不会用到 直到出现它们两栈顶不同。然后我们将其中大小更大的栈的栈顶丢到 里(至于为什么是更大的,我们在后面说)。因为我们去重后,一定颜色是相间的,所以就可以一直进行消除栈顶的操作。
接着是中间的消除过程。
显然如果 的顶端相同,那么我们可以消除,策略是将大小更大的顶端消除。欸,你会发现这里和上面都是更大的,有什么联系吗?有的,你会发现,我们这样做,可以控制 栈两者的差尽量接近。当我们 中有元素后,我们做上面的操作,就可以把 两个栈的元素之差控制在 1 以内。至于证明比较显然,你可以自己手动模拟。
但是控制在 1 以内有什么理由吗?如果不控制在 1 之内,就会出现某一个栈空了,但另外一个栈就像夹心蛋糕一样,此时的消除就会花费花费很多额外的代价。而控制在 1 之内就没有这些代价,因为最后的状态十分简洁。
现在就在于处理终止状态。根据上面的操作方法,条件不难得出。
显然终止条件只能是 。此时栈中的元素一定是尽可能简洁的。
此时分类讨论一波, 的栈顶和 的栈顶是否相同。如果相同,那么一定是 ,再加上 的贡献就行。
如果不同,就讨论是否 中有数,此时有可能 或者出现其中一个为 2 的情况。
讨论完之后,你就做完了。
CODE
CPP#include <bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define se second
#define pb emplace_back
using namespace std;
constexpr int N=1e5+5;
int n,typ;
int a[N],b[N],c[N];
int ida,idb,idc;
vector<pii>ans;
void solve()
{
scanf("%d%d",&n,&typ);
ans.clear(),ida=idb=idc=0;
for(int i=1,x;i<=n;i++)
{
scanf("%1d",&x);
if(x!=a[ida])a[++ida]=x;
}
for(int i=1,x;i<=n;i++)
{
scanf("%1d",&x);
if(x!=b[idb])b[++idb]=x;
}
while(ida+idb>2)
{
if(ida && idb && a[ida]==b[idb])
{
if(ida>=idb)ans.pb(1,2),ida--;
else ans.pb(2,1),idb--;
continue;
}
if(idc)
{
if(ida && a[ida]==c[idc])ans.pb(1,3),ida--;
else if(idb && b[idb]==c[idc])ans.pb(2,3),idb--;
}
else
{
if(ida>=idb)ans.pb(1,3),c[++idc]=a[ida--];
else ans.pb(2,3),c[++idc]=b[idb--];
}
}
if(a[ida]==b[idb])
{
ans.pb(1,2);
if(idc)ans.pb(3,1);
}
else if(idc)
{
// cerr<<"1:";
if(ida!=idb)
{
// cerr<<"1:";
if(ida==2)ans.pb(1,2),b[++idb]=a[ida--];
else ans.pb(2,1),a[++ida]=b[idb--];
}
if(c[idc]==a[ida])ans.pb(3,1);
else ans.pb(3,2);
}
else
{
// cerr<<"2:";
if(ida==2)ans.pb(1,2);
else if(idb==2)ans.pb(2,1);
}
printf("%d\n",(int)ans.size());
if(typ==1)return;
for(auto [x,y]:ans)printf("%d %d\n",x,y);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("data.in","r",stdin);
#endif
int T;scanf("%d",&T);
while(T--)solve();
return 0;
}
看在讲的如此详细的份上,点个赞再走吧!
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...