zoukankan      html  css  js  c++  java
  • 「Luogu P5080 Tweetuzki 爱序列」

    题目大意

    给出一些数,需要求出 (frac{a_{i+1}}{3}=a_i)(a_{i+1}=2 imes a_i) 时最长的序列 (a).

    分析

    可以发现符合条件的序列 (a) 中不会出现重复的数字,而且对于一个数它的下一个位置最多只有两种情况,于是问题就变成了无环有向图最长链,这样就可以想到记忆化搜索,(f_i) 表示 (i) 为起点时的最长链长度,为了记录下路径,所以还需要用一个 (nxt_i) 表示 (i) 的下一个位置时什么,最后直接输出就好了.

    代码

    #include<bits/stdc++.h>
    #define REP(i,first,last) for(int i=first;i<=last;++i)
    #define DOW(i,first,last) for(int i=first;i>=last;--i)
    using namespace std;
    const int MAXN=1e6+7;
    int N;
    struct Edge//链式前向星
    {
    	int to,next;
    }edge[MAXN*2];
    int edge_head[MAXN];
    int edge_cnt=0;
    #define TO_POINT(now) for(int edge_i=edge_head[now];edge_i;edge_i=edge[edge_i].next)
    #define TO edge[edge_i].to
    void AddEdge(int f,int t)
    {
    	edge[++edge_cnt].to=t;
    	edge[edge_cnt].next=edge_head[f];
    	edge_head[f]=edge_cnt;
    }
    bool visit[MAXN];
    long long arr[MAXN];//原数组
    long long a[MAXN];//去重以后的数组
    int f[MAXN];//记录每个位置的最长链长度
    int Find(long long num)//二分查找是否存在这个数
    {
    	int left=1,right=N,middle;
    	while(left<=right)
    	{
    		middle=(left+right)>>1;
    		if(a[middle]>=num)
    		{
    			right=middle-1;
    			if(a[middle]==num)
    			{
    				return middle;
    			}
    		}
    		else
    		{
    			left=middle+1;
    		}
    	}
    	return 0;
    }
    int nxt[MAXN];//记录下一个位置
    void DFS(int now)//DFS
    {
    	if(f[now])//如果搜索过就不需要搜索了
    	{
    		return;
    	}
    	f[now]=1;//开始的长度为1
    	TO_POINT(now)
    	{
    		DFS(TO);
    		if(f[TO]+1>f[now])//找到在自己连出的边中的最长链长度
    		{
    			f[now]=f[TO]+1;
    			nxt[now]=TO;//记录下一个位置
    		}
    	}
    }
    int main()
    {
    	scanf("%d",&N);
    	REP(i,1,N)
    	{
    		scanf("%lld",&arr[i]);
    	}
    	sort(arr+1,arr+1+N);
    	arr[0]=arr[1]-1;
    	int cnt=0;
    	REP(i,1,N)//去重
    	{
    		if(arr[i]!=arr[i-1])
    		{
    			a[++cnt]=arr[i];
    		}
    	}
    	N=cnt;
    	int l;
    	REP(i,1,N)//对于每一个点连边
    	{
    		if(a[i]%3==0)//需要判断整除
    		{
    			l=Find(a[i]/3);
    			if(l)
    			{
    				AddEdge(i,l);
    			}
    		}
    		l=Find(a[i]*2);
    		if(l)
    		{
    			AddEdge(i,l);
    		}
    	}
    	int answer=0,st;
    	REP(i,1,N)//如果没有访问过就DFS这个位置
    	{
    		if(!f[i])
    		{
    			DFS(i);
    		}
    		if(f[i]>answer)//记录下最长链的开头
    		{
    			answer=f[i];
    			st=i;
    		}
    	}
    	printf("%d
    ",answer);//输出答案
    	int now=st;
    	while(now)
    	{
    		printf("%lld ",a[now]);
    		now=nxt[now];
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    实现一个最简单的flask应用程序
    python常识
    Flex布局
    ES6的promise的学习
    通过正则获取url参数
    dom0级事件和dom2级事件
    sea.js总结
    跨域的几种方式
    人生苦短,生命也就一次,机会也就一次
    新开的博客先和大家打个招呼吧!
  • 原文地址:https://www.cnblogs.com/Sxy_Limit/p/12372098.html
Copyright © 2011-2022 走看看