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\)
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
CF995E Number Clicker 解題報告