[3月集训]D1T2

这里写图片描述
这里写图片描述

sol:

考虑到汉诺塔 游戏。中间显然会有一个状态,使得最大的盘子在a柱,目标是c,其他盘子都在b。那我们考虑把这个状态称为中间状态。那么现在考虑怎么把起始的盘子弄到这个中间状态,再把终止的盘子弄到这个中间状态。显然对于每一个最大的盘子,他在对应的位置上我们就不管他了,否则他在a,目标是c,肯定其他盘子叠到b,然后a->c,再花2^n-1步把叠好的盘子移到c。这个步数是经典结论。
结果我们样例都过不了。我们发现还有一种中间状态,他可以是最大的盘子在a,目标是c,先把其他盘子移到c,然后a到b,再把其他盘子到a,最大的盘子再到c。那就是最后还要再花2^{n-1}+1步

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=1e6+7;
int n,m,ans1[N],ans2[N],pos1[N],pos2[N];
inline void calc(int *ans,int *pos,int id)
{
    for(int i=n-1;i>=1;--i)
    {
        if(pos[i]!=id)
        {
            ans[i-1]++;
            id=6-pos[i]-id;
        }
    }
}
inline void simplex(int *a)
{
    for(int i=1;i<=n;++i) a[i]+=a[i-1]/2,a[i-1]&=1;
}
inline bool cmp(int *a,int *b)
{
    for(int i=n;i>=1;--i)
    {
        if(a[i]==b[i]) continue;
        if(a[i]) return 0;
        else return 1;
    }
    return 0;
}
const int pyz=998244353;
int Pow[N];
inline void print(int *a)
{
    ll ans=0;
    Pow[0]=1;
    for(int i=1;i<=n;++i) Pow[i]=Pow[i-1]*2%pyz;
    for(int i=0;i<=n;++i) ans=(ans+(ll)a[i]*Pow[i]%pyz)%pyz;
    cout<<ans;
}
int main()
{
//  freopen("b.in","r",stdin);
    cin>>n;
    for(int i=1;i<=3;++i)
    {
        cin>>m;
        for(int j=1;j<=m;++j)
        {
            int x;
            scanf("%d",&x);
            pos1[x]=i;
        }
    }
    for(int i=1;i<=3;++i)
    {
        cin>>m;
        for(int j=1;j<=m;++j)
        {
            int x;
            scanf("%d",&x);
            pos2[x]=i;
        }
    }
    while(pos1[n]==pos2[n]) --n;
    if(!n)
    {
        printf("0\n");
        return 0;
    }
    calc(ans1,pos1,6-pos1[n]-pos2[n]);
    calc(ans1,pos2,6-pos1[n]-pos2[n]);
    ans1[0]++;
    simplex(ans1);
    calc(ans2,pos1,pos2[n]);
    calc(ans2,pos2,pos1[n]);
    ans2[n-1]++;ans2[0]++;
    simplex(ans2);
    if(cmp(ans1,ans2)) print(ans1);
    else print(ans2);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值