首页 > 其他分享 >P5080 Tweetuzki 爱序列 题解

P5080 Tweetuzki 爱序列 题解

时间:2022-08-17 23:33:06浏览次数:73  
标签:pre ma int 题解 Tweetuzki 序列 P5080 define

题目传送门

更好地阅读体验

题目大意

Tweetuzki 有一个长度为 \(n\) 的序列 \(a_1, a_2, \cdots, a_n\)。

他希望找出一个最大的 \(k\),满足在原序列中存在一些数 \(b_1, b_2, \cdots, b_k\)(可打散在原序列中的顺序),满足对于任意的 \(i(1 \le i < k)\),\(b_i \div 3 = b_{i+1}\)(这时 \(b_i\) 必须能够被 \(3\) 整除)或 \(b_i \times 2 = b_{i+1}\)。并输出这个序列。

解题思路

有个很明显的性质:每个数只会出现一次。(大概是因为 \(2\) 和 \(3\) 互质)

可以感性理解一下:每次除以 \(3\) 或乘以 \(2\) 之后,得到的因子 \(2\) 永远不可能再失去,失去的 \(3\) 也不可能再回来。

所以可以考虑建边,对于每个 \(x\) 向 \(x \div 3(x\%3=0)\) 和 \(2x\) 连边有向边,前提是这两个目标数存在。

这样很明显就构成了一个 DAG。要求的就是最长链,考虑拓扑排序和 DP(很基础的)。

还有一点就是要记录每个点转移来的点是谁,最后 dfs 输出路径。

具体细节看代码吧。

#include<bits/stdc++.h>
#define Code using
#define from namespace
#define yolanda std
Code from yolanda;
#define int long long
inline int read(){
	int sum=0,f=1;char a=getchar();
	while(a<'0' || a>'9'){if(a=='-') 	f=-1;a=getchar();}
	while(a>='0' && a<='9') 	sum=sum*10+a-'0',a=getchar();
	return sum*f;
}

unordered_map<int,int> pre,d,f;//直接用map就不用离散化了
//f[x]就是到当前点的最长长度
int n,ma,ans;
int a[100005];

void topo(){//拓扑排序
	queue<int> q;
	for(int i=1;i<=n;++i)
		if(!d[a[i]])	q.push(a[i]);
	while(q.size()){
		int x=q.front();q.pop();
		if(f[x]>ma)	ma=f[x],ans=x;//ma是最大值,ans是终止点
		if(f[x*2]){
			--d[x*2];
			if(f[x]+1>f[x*2])	f[x*2]=f[x]+1,pre[x*2]=x;
			if(!d[x*2])	q.push(x*2);
		} 
		if(x%3==0 && f[x/3]){
			--d[x/3];
			if(f[x]+1>f[x/3])	f[x/3]=f[x]+1,pre[x/3]=x;
			if(!d[x/3])	q.push(x/3);
		} 
	}
}
void print(int x){//输出
	if(!x)	return;
	print(pre[x]);
	printf("%lld ",x);
}

signed main(){
	
	cin>>n;
	for(int i=1;i<=n;++i)
		a[i]=read(),f[a[i]]=1;
	sort(a+1,a+n+1);
	n=unique(a+1,a+n+1)-a-1;
	for(int i=1;i<=n;++i){//建边
		if(f[a[i]*2])	++d[a[i]*2];
		if(a[i]%3==0 && f[a[i]/3])	++d[a[i]/3];
	}
	topo();
	printf("%lld\n",ma);
	print(ans);
	
	return 0;
}

标签:pre,ma,int,题解,Tweetuzki,序列,P5080,define
From: https://www.cnblogs.com/yolanda-yxr/p/16597229.html

相关文章

  • IOI 2022 简要题解
    考前写题解增加RP。D1T1:考虑按照列DP。对于每一列选择的鱼的区间进行决策。每列中被选择的y坐标最大的鱼,需要被左面或右面覆盖。假设我们决策好了前i列的方案,考虑第i列......
  • [题解] HDU 5115 Dire Wolf 区间DP
    考虑先枚举所有的物品中最后拿走的,这样就分成了2个子问题,即先拿完左边的,再拿完右边的,最后拿选出的那个。令dp(i,j)表示拿完[i,j]所有物品的最小代价。你可能会说,我们拿[i,j......
  • 题解 CF1575D【Divisible by Twenty-Five】
    值域非常小,其中只有\(4\times10^6\)个数是\(25\)的倍数,因此可以暴力枚举所有位数正确的\(25\)的倍数,然后检查是否合法。检查方法就是枚举每一位,如果是数字就必须一......
  • CF Round 814 Div2 题解
    A题ChipGame(签到)给定一个\(n\)行\(m\)列的方格矩阵,左下角是\((1,1)\),右上角是\((m,n)\)。(采取了类似笛卡尔坐标系的表示法,不是普通的\(x\)行\(y\)列)Burenka......
  • CF578C题解
    看到题面的第一眼是这玩意儿关于x是单谷的,证明稍微想了一下:设\(f[k]\)和\(g[k]\)是原序列中长度为\(k\)的子区间的最大子区间和最小子区间,给定\(x\)时答案就相......
  • CF1719C Fighting Tournament 题解
    思路根据题意,很容易看出,每个人都完成一次比赛后,即完成\(n-1\)轮之后,力量值最大的人会留在第一的位置,且在第\(n-1\)轮完成后,除了力量值最大的人,其他人的胜场数都不会再......
  • CF1719A Chip Game 题解
    题目传送门。思路当其中一个人不能动的时候,这个人一定位于点\((n,m)\)上。令点\((n,m)\)为终点。当\(n\)和\(m\)都是奇数或当\(n\)和\(m\)都是偶数时,赢的人......
  • CF1719B Mathematical Circus 题解
    一道不错的构造题。思路先说一句废话,能被\(4\)整除的数在除以\(2\)之后得到的数还是一个偶数。我们可以根据\(k\)的奇偶性以及\(k\)除以\(2\)之后的奇偶性分......
  • BSOJ7020题解
    脑抽了。考场上应该做掉这题的。所以实际挂分从100pts变成了200pts/fn/fn/fn考虑用一个二元组来维护链,\((f,g)\)表示这个集合的所有链的点权和为\(f\),有\(g\)条链,目......
  • 针对“RuntimeError: each element in list of batch should be of equal size” 问题
    第一次运行代码出现了这个问题:这个问题的出现主要来源于DataLoader类中的collate.py文件造成的问题,由于每个batch里的长度不一致,因此导致出现了该问题。通过百度方法和......