CF232C Doe Graphs

  传送门

Solution:  (不理解时对着图研究一下就清楚啦!!!)

sm[i]为|D(i)|  (x,y,n)为x,y在D(n)中的最短路

已知sm[i-1]+1为D(i)的割点

于是x-y的最短路就可以分为三种情况:

  • x<sm[n-1]+1&&y>=sm[n-1]+1 
  • x<sm[n-1]+1&&y<sm[n-1]+1
  • x>=sm[n-1]+1&&y>=sm[n-1]+1

下面我们就来讨论这三种情况

  • x在图D(n-1)上,y在图D(n-2)上,它们的最短路必过割点sm[n-1]+1

  我们只要分别求解x,y到割点的最短路即可

  y到割点的最短路即为(1,y-sm[n-1],n-2)

  x到割点的最短路却有两种可能 (1,x,n-1)+1或(x,sm[n-1],n-1)+1 这两种情况取小即可

  • x,y都在图D(n-1)上

  一定要注意这里 x-y的最短路并不一定局限于D(n-1) 还有可能经过割点

  所以这里有两种情况:(x,y,n-1)

    又有两种经过割点的方式: (1,x,n-1)+(y,sm[n-1],n-1)+2 和 (1,y,n-1)+(x,sm[n-1],n-1)+2

    同样取小即可

  • x,y都在图D(n-2)上

  是最简单的一种情况啊,为(x,y,n-2)

  但是如果这样子递归下去是会TLE的,所以我们要优化一下

  发现只要求出图D(i)中x,y点到1和sm[i]的最短路就可以了

  于是预处理出就可以了

  d1[i]为(1,x,i) d2[i]为(x,sm[i],i) d3[i]为(1,y,i) d4[i]为(y,sm[i],i)

  pre函数看图研究一下就可以理解啦

  

CODE:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define R register
 5 #define go(i,a,b) for(R int i=a;i<=b;i++)
 6 #define ll long long
 7 #define M 105
 8 using namespace std;
 9 ll rd()
10 {
11     ll x=0,y=1;char c=getchar();
12     while(c<'0'||c>'9'){if(c=='-')y=-1;c=getchar();}
13     while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
14     return x*y;
15 }
16 ll T,n,sm[M],d[M],d1[M],d2[M],d3[M],d4[M];
17 void pre(ll x,ll nw,ll t1[],ll t2[])
18 {
19     if(nw==0) return ;
20     if(nw==1) {t1[1]=(x==2);t2[1]=(x==1);return ;}
21     if(x<=sm[nw-1])
22     {
23         pre(x,nw-1,t1,t2);
24         t1[nw]=min(t1[nw-1],t2[nw-1]+2);
25         t2[nw]=min(t1[nw-1],t2[nw-1])+d[nw-2]+1;
26     }
27     else
28     {
29         pre(x-sm[nw-1],nw-2,t1,t2);
30         t1[nw]=t1[nw-2]+1;
31         t2[nw]=t2[nw-2];
32     }
33 }
34 ll qy(ll x,ll y,ll nw)
35 {
36     if(nw<=1) return x!=y;
37     if(x<sm[nw-1]+1&&y>=sm[nw-1]+1) return min(d1[nw-1],d2[nw-1])+d3[nw-2]+1;
38     if(x<sm[nw-1]+1&&y<sm[nw-1]+1) return min(qy(x,y,nw-1),min(d1[nw-1]+d4[nw-1],d2[nw-1]+d3[nw-1])+2);
39     return qy(x-sm[nw-1],y-sm[nw-1],nw-2);
40 }
41 int main()
42 {
43     freopen("1.in","r",stdin);
44     freopen("1.out","w",stdout);
45     T=rd();n=rd();n=min(n,(ll)80);
46     sm[0]=1;sm[1]=2;d[0]=0;d[1]=1;//d[i]表示D(i)的1到sm[i]结点的最短距离
47     go(i,2,n) sm[i]=sm[i-1]+sm[i-2],d[i]=d[i-2]+1;n=min(n,(ll)80);
48     while(T--)
49     {
50         ll x=rd(),y=rd();if(x>y)swap(x,y);
51         pre(x,n,d1,d2);pre(y,n,d3,d4);
52         printf("%lld\n",qy(x,y,n));
53     }
54     return 0;
55 }
View Code

后:

真的没那么难啊 仔细分析细心一点就没有问题啦

然而 我还是调了一晚上qwq 因为longlong 要哭了...

如果哪里不懂一定要问我 因为可能我也不懂那我就要感谢你发现我没懂的地方啦

然后我们可以一起研究啦啦啦

猜你喜欢

转载自www.cnblogs.com/forward777/p/10372248.html