CF995E Number Clicker 解题报告

CF995E Number Clicker

题目描述

Allen is playing Number Clicker on his phone.

He starts with an integer u u on the screen. Every second, he can press one of 3 buttons.

Turn \(u \to u+1 \pmod{p}\).

Turn \(u \to u+p-1 \pmod{p}\).

Turn \(u \to u^{p-2} \pmod{p}\).

Allen wants to press at most 200 buttons and end up with v v on the screen. Help him!

输入输出格式

输入格式:

The first line of the input contains 3 positive integers: \(u, v, p\)( \(0 \le u, v \le p-1\) , \(3 \le p \le 10^9 + 9\) ). \(p\) is guaranteed to be prime.

输出格式:

On the first line, print a single integer \(\ell\) , the number of button presses.

On the second line, print integers \(c_1, \dots, c_\ell\), the button presses.

For \(1 \le i \le \ell\) , \(1 \le c_i \le 3\).

We can show that the answer always exists.


长见识了。

发现这道题可以建成一个比较随机的图。

根据生日攻击,我们基本上只需要图的点数\(p\)开根号个\(\sqrt p\),就可以找到答案了。

于是进行双向搜索,合并答案即可。


Code:

#include <cstdio>
#include <map>
#define ll long long
const int N=2e5;
ll u,v,p,q[N+10],l=1,r=0,s[N],tot;
std::map <ll,ll > pre,used,opt,pre0,opt0;
void in(ll now,ll to,ll op)
{
    if(!used[to])
    {
        used[to]=1;
        opt[to]=op;
        pre[to]=now;
        q[++r]=to;
    }
}
ll quickpow(ll d,ll k)
{
    ll f=1;
    while(k)
    {
        if(k&1) f=f*d%p;
        d=d*d%p;
        k>>=1;
    }
    return f;
}
int bfs0()
{
    q[++r]=u;
    while(l<=r&&r<=N)
    {
        ll now=q[l++];
        if(now==v)
        {
            while(now!=u) s[++tot]=opt[now],now=pre[now];
            printf("%lld\n",tot);
            for(int i=tot;i;i--)
                printf("%lld ",s[i]);
            return 1;
        }
        ll to=(now+1)%p;
        in(now,to,1);
        to=(now+p-1)%p;
        in(now,to,2);
        to=quickpow(now,p-2);
        in(now,to,3);
    }
    return 0;
}
void in0(ll now,ll to,ll op)
{
    if(!used[to])
    {
        used[to]=1;
        opt0[to]=op;
        pre0[to]=now;
        q[++r]=to;
    }
}
ll tmp;
void swap(ll &x,ll &y){tmp=x,x=y,y=tmp;}
void bfs1()
{
    used.clear();
    l=1,r=0;
    q[++r]=v;
    while(l<=r&&r<=N)
    {
        ll now=q[l++];
        if(pre.find(now)!=pre.end())
        {
            ll t=now;
            while(now!=u) s[++tot]=opt[now],now=pre[now];
            for(int i=1;i<=tot>>1;i++) swap(s[i],s[tot+1-i]);
            now=t;
            while(now!=v) s[++tot]=opt0[now],now=pre0[now];
            printf("%lld\n",tot);
            for(int i=1;i<=tot;i++)
                printf("%lld ",s[i]);
            return;
        }
        ll to=(now+1)%p;
        in0(now,to,2);
        to=(now+p-1)%p;
        in0(now,to,1);
        to=quickpow(now,p-2);
        in0(now,to,3);
    }
}
int main()
{
    //freopen("dew.out","w",stdout);
    scanf("%lld%lld%lld",&u,&v,&p);
    if(bfs0()) return 0;
    bfs1();
    return 0;
}


2018.10.9

posted @ 2018-10-09 20:29  露迭月  阅读(594)  评论(0编辑  收藏  举报