• 【题目】CF232C Doe Graphs


    CF232C Doe Graphs

    一看到题第一时间想到的大概是点的个数满足斐波那契数列的关系,即(fib_i=fib_{i-1}+fib_{i-2}),在题目中可以得知(fib_{0}=1,fib_{1}=2)(这里的(fib_{i})即为文中的(D_{i})

    然后考虑怎么求第n次的i到j的距离呢?自然想到这可能和上一次有关系,那么有什么关系呢?我们自然而然想到了递推(不习惯用f,这里用dp取代)

    (dp_{n,i,j})表示第n层,从i到j至少需要走的路径长度,然后考虑它怎么转移

    下面分三种情况:

    1. (i,j≤fib_{n-1}),即两个点都在第(n-1)的图上,这时候考虑(dp_{n,i,j})等于什么,显然得出(dp_{n,i,j}=min(dp_{n-1,i,j}) //即直接从这两个点走,不经过第n层新增的点

    (,min(dp_{n-1,1,i}+dp_{n-1,j,fib_{n-1}}+2,dp_{n-1,i,fib_{n-1}}+dp_{n-1,1,j}+2)) //即经过新加的((1,fib_{n-1}+1))((fib_{n-1},fib_{n-1}+1))的边

    1. (i≤fib_{n-1},j>fib_{n-1}) 可以试想把j移到j-fib_{n-1}的位置,即原图形的镜像位置(莫名皇室)这个玩意儿愿读者自行画图理解那么它经历什么呢,显然是(min(dp_{n-1,1,i},dp_{n-1,i,fib_{n-1}})) //即i点到1或者(fib_{n-1})的距离

    (+dp_{n-2,1,j-fib_{n-1}}+1) //即j点到1点的距离

    若i,j相反则swap一下即可

    1. (i>fib_{n-1},j>fib_{n-1}) 其实此时的位置就相当于它与第(n-1)层的镜面位置

    (dp_{n,i,j}=dp_{n-2,i-fib_{n-1},j-fib_{n-1}})

    此时处理好了dp,如果你这是以为大功告成了,那我告诉你你想简单了,想一想就知道这个dp有多庞大!!那肿么办呢?

    通过观察发现这些式子中出现了很多很多个形如(dp_{n-1,1,x})(dp_{n-1,x,fib_{m}})的式子,而且其它式子都可以通过这个得到!!

    然后突然syx笑出了声,这不就直接处理一下就行了吗?!(然后笑着笑着就处理了一个晚上)

    这怎么处理呢?咱又开始找规律了

    因为对于每个询问,x是固定的,也就是说每层的dp值是固定的,那我们干脆把dp重新定义一下,(dp_{i,1/2,1/2})表示对于第i层图,当前是给定的两个点中的第一个点还是第二个点,是1到x的距离还是x到(fib_{n-1})的距离

    我们发现对于两个点处理的方式都是一样的(因为只需要算1到x,x到(fib_{n-1})的距离),所以这里只讲一个了

    我们先来看(dp_{i,1/2,1})

    不难发现,这个特好处理

    (x≤fib_{n-1})时,(dp_{n,1,x}=min(dp_{n-1,1/2,1},dp_{n-1,1/2,2}+2)) 为什么呢?还是考虑此张图与上一张图的关系,从1到x就以为这1可以连到(fib_{n-1}+1)的节点上,然后再由(fib_{n-1}+1)的节点连到(fib_{n-1})的节点,那么你瞧瞧,你瞧瞧,从x到(fib_{n-1})的距离等于什么?等于(dp_{n-1,1/2,2}+2)啊!!于是再与直接不管第n层图新增的点相比较,就求出来了

    (x>fib_{n-1})时,就更好玩了,不就和之前讲到的一样,镜像一下,(dp_{n,1/2,1}=dp_{n-2,1/2,1}+1)

    接着看(dp_{i,1/2,2})

    (x≤fib_{n-1})时,(dp_{n,1/2,2}=min(dp_{n-1,1/2,1},dp_{n-1,1/2,2})+(n-1)/2+1) 这个玩意儿最重要的就是(n-1)/2+1的意思,此处希望读者先自行思考,然后看下一行

    那么这个式子是什么意思呢?你考虑一下从第n层图中新增的第一个节点(即编号(fib_{n-1}+1)的节点)到最后一个节点的距离,它恰好是(n-1)/2(n=0或n=1时要特殊处理),然后再加上1到(fib_{n-1}+1)或者(fib_{n-1})(fib_{n-1}+1)的一条边,距离一共是这么长

    (x>fib_{n-1})时,也是镜像一下,(dp_{n,1/2,2}=dp_{n-2,1/2,2})

    于是你懂该怎么做了!!但是劝大家自己码一下,这题真的真的真的需要很锻炼细心,哪怕是先看一遍我的code再自己码也要码一遍

    然后就开始代码大放送了!!

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    #define pb push_back
    #define mk make_pair
    #define fir first
    #define sec second
    inline int read() {
    	int x(0),neg(1);char ch(getchar());
    	while(!isdigit(ch)) {if (ch=='-') neg=-1;ch=getchar();}
    	while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	return x*neg;
    }
    const int MAXN=100;
    int n,fib[85];
    int dp[MAXN+5][2][2];
    inline void DP_X(int tot,int x) {
    	if (tot==0) {
    		dp[tot][1][1]=dp[tot][1][2]=0;
    	}
    	else if (tot==1) {
    		if (x==1) dp[tot][1][1]=0; else dp[tot][1][1]=1;
    		if (x==2) dp[tot][1][2]=0; else dp[tot][1][2]=1;
    	} 
    	else {
    		if (x<=fib[tot-1]) {
    			DP_X(tot-1,x);
    			dp[tot][1][1]=min(dp[tot-1][1][1],dp[tot-1][1][2]+2);
    			dp[tot][1][2]=min(dp[tot-1][1][1],dp[tot-1][1][2])+(tot-1)/2+1;
    		}
    		else {
    			DP_X(tot-2,x-fib[tot-1]);
    			dp[tot][1][1]=dp[tot-2][1][1]+1;
    			dp[tot][1][2]=dp[tot-2][1][2];
    		}
    	}
    }
    inline void DP_Y(int tot,int y) {
    	if (tot==0) {
    		dp[tot][2][1]=dp[tot][2][2]=0;
    	}
    	else if (tot==1) {
    		if (y==1) dp[tot][2][1]=0; else dp[tot][2][1]=1;
    		if (y==2) dp[tot][2][2]=0; else dp[tot][2][2]=1;
    	} 
    	else {
    		if (y<=fib[tot-1]) {
    			DP_Y(tot-1,y);
    			dp[tot][2][1]=min(dp[tot-1][2][1],dp[tot-1][2][2]+2);
    			dp[tot][2][2]=min(dp[tot-1][2][1],dp[tot-1][2][2])+(tot-1)/2+1;
    		}
    		else {
    			DP_Y(tot-2,y-fib[tot-1]);
    			dp[tot][2][1]=dp[tot-2][2][1]+1;
    			dp[tot][2][2]=dp[tot-2][2][2];
    		}
    	}
    }
    inline int query(int tot,int x,int y) {
    	if (tot==0) return 0;
    	else if (tot==1) {
    		if (x==y) return 0;
    		return 1;
    	}
    	else if (x<=fib[tot-1]) {
    		if (y<=fib[tot-1]) {
    			return min(query(tot-1,x,y),min(dp[tot-1][1][1]+dp[tot-1][2][2],dp[tot-1][1][2]+dp[tot-1][2][1])+2);
    		}
    		else {
    			return min(dp[tot-1][1][1],dp[tot-1][1][2])+dp[tot-2][2][1]+1;
    		}
    	}
    	else {
    		return query(tot-2,x-fib[tot-1],y-fib[tot-1]);
    	}
    }
    signed main() {
    	int m=read(),n=read();
    	fib[0]=1;fib[1]=2;
    	n=min(n,78ll);
    	for (int i=2;i<=n;++i) fib[i]=fib[i-1]+fib[i-2];
    	for (int i=1;i<=m;++i) {
    		int x(read()),y(read());
    		memset(dp,0,sizeof(dp));
    		if (x>y) swap(x,y);
    		DP_X(n,x);DP_Y(n,y);
    		printf("%lld
    ",query(n,x,y));
    	}
    	puts("");
    }
    
  • 相关阅读:
    iframe显示高度自适应 兼容多浏览器
    Asp.Net在Global.asax中实现URL 的重写
    文件流下载 ASP.NET
    Asp.Net实现全局定时器功能
    C#中获取本机IP地址,子网掩码,网关地址
    Asp.Net缓存实例
    Google API 天气数据缓存到一个XML中
    获取服务器信息
    C# NET 中英混合字符串截断实例
    Asp.Net实现长文章分页显示功能
  • 原文地址:https://www.cnblogs.com/sunyx20060115/p/14961605.html
Copyright © 2020-2023  润新知