Paint Pearls

题目大意:lee要把一串珠子涂成目标颜色,给一段珠子染色的代价是这一段珠子中珠子种类数的平方,求怎么染色才能花费最小

我的思路:开始先想到用贪心,发现情况太多了,贪不了。然后想到用dp考虑所有情况,看上去可行,但是t了,我先来讲讲我的思路,看看大家有没有什么优化的方案
首先用双指针预处理出来b[][]数组,b[i][j]表示i到b[i][j]中恰好包含j种珠子。当然j<=根号m(珠子总数),因为如果>根号m了,还不如一个一个选划得来

预处理完后,就开始dp了。

用dp[i]表示以第i颗珠子结尾的最小花费是多少。

 状态转移方程是:dp[i]=min(dp[i],dp[b[i][j]-1]+j*j)

尝试从b[i][j](0<j<根号i)这个点来更新i号点,不重不漏考虑所有情况,时间复杂度m根号m

但是t了,可能是常数大了

tle代码如下:

#include<bits/stdc++.h>
using namespace std;
#define sf(x) scanf("%d",&x)
#define sff(x,y) scanf("%lld%lld",&x,&y)
//#define endl '\n'
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define pf(x) printf("%lld",x)
#define pii pair<int,int> 
#define f first 
#define s second
//#define int long long


//
const int N=5e4+10,M=230;
int m;
int a[N];
int b[N][M];
int dp[N];
int sum[N];
vector<int> ve;
//

int erfen(int x)
{
	int l=-1,r=ve.size();
	while(l+1<r)
	{
		int mid =l+r>>1;
		if(ve[mid]<=x) l=mid;
		else r=mid;
	}
	return l;
}

//


void solve()
{
	while(~sf(m))
	{
		ve.clear();
		for(int i=1;i<=m;i++){
//			cin>>a[i];
			sf(a[i]);
			ve.push_back(a[i]);
			dp[i]=0x3f3f3f3f;
			for(int j=1;j*j<=m;j++) b[i][j]=0;
		}
		
		//离散化
		sort(ve.begin(),ve.end());
		ve.erase(unique(ve.begin(),ve.end()),ve.end());
		
		for(int i=1;i<=m;i++)sum[i-1]=0, a[i]=erfen(a[i]);
		
        //预处理
		int cnt=0;
		for(int i=1;i*i<=m;i++)
		{
			for(int l=1,r=0;l<=m;l++)
			{
				while(r<=m&&cnt<=i){
					if(cnt==i){
						b[r][i]=l;
					}
					int x=a[++r];
					if(!sum[x]) cnt++;
					sum[x]++;
				}
				if(!(--sum[a[l]])) cnt--;
			}
		}
		//dp
		for(int i=1;i<=m;i++){
			dp[i]=dp[i-1]+1;
			for(int j=1;j*j<=i;j++){
				if(b[i][j])
				dp[i]=min(dp[i],dp[b[i][j]-1]+j*j);//cout<<i<<" "<<j<<" "<<b[i][j]<<endl;
			}
		}
		printf("%d\n",dp[m]);
	}
}
signed main()
{
//	IOS;
	int _=1;
//	cin>>_;23
	while(_--)
		solve();
	return 0;
}

后来喵了眼题解,发现可以用一个双链表代替预处哩,而且最快时间复杂度可以到o(m),但是极端情况也要到m根号m,题目也没说有多少组,这就很头疼。

怎么用双链表解决呢,见代码注释
ac代码:

#include<bits/stdc++.h>
using namespace std;
#define sf(x) scanf("%d",&x)
#define sff(x,y) scanf("%d%d",&x,&y)
#define endl '\n'
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define pf(x) printf("%lld",x)
#define pii pair<int,int> 
#define f first 
#define s second
//#define int long long



//
const int N=5e4+10;
int l[N],r[N],nel[N],ner[N],e[N];
int m,lr,rr,idx;
int a[N],dp[N];
//

void init()//初始化,双链表
{
	lr=1,rr=2;
	ner[lr]=2,nel[rr]=1;
	idx=3;
}

void insert_r(int x)//从右根节点插入元素
{
	ner[idx]=rr;
	nel[idx]=nel[rr];
	e[idx]=x;
	ner[nel[rr]]=idx;
	nel[rr]=idx++;
}

void delate(int x)//删除编号为x的点
{
	ner[nel[x]]=ner[x];
	nel[ner[x]]=nel[x];
}
//


void solve()
{
	
	while(~sf(m)){
		
		map<int,int> mp;//mp存已经出现过的点
		init();
		
		for(int i=1;i<=m;i++)
		{
			sf(a[i]);
			dp[i]=0x3f3f3f3f;
			insert_r(i); //先全部插入插入双链表
		}
		dp[1]=1; 
		for(int i=1;i<=m;i++)
		{
			int id=i+2;//每个数的编号是下表+2,因为idx初始为3
			if(!mp.count(a[i])) mp[a[i]]=id;//如果该元素还没有出现过,则记录他的下标,顺便维护该元素已经出现过了
			else{
				delate(mp[a[i]]);//否现删除之前的遍号,保留现在的编号,每种珠子只保留最右边的,因为左边重复的对i的种类数不会有任何影响,大家可以举个例子试一下
				mp[a[i]]=id;
			}
			int cnt=0;
			for(int k=nel[id];k!=0;k=nel[k])
			{
				cnt++;
				int j=e[k];//cnt表示j到k之间有多少种珠子,不包括j这号点
				dp[i]=min(dp[i],dp[j]+cnt*cnt);//更新方式同理
				if(cnt*cnt>k) break;//优化方式同理
			}
			
		}
		
		printf("%d\n",dp[m]);		
	}
}
signed main()
{
//	IOS;
	int _=1;
//	cin>>_;
	while(_--)
		solve();
	return 0;
}

谢谢大家

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《编程珠玑》是一本经典的计算机编程书籍,由Jon Bentley所著。书中作者以宝石的形式,以自己在编程领域的经验和思考作为原料,展现了许多精彩的编程技巧和解决问题的思路。 这本书被誉为计算机界的经典之作,其价值不仅在于作者分享的个人经验,更在于其中蕴含的许多智慧和洞见。书中的每个章节都涵盖了一个独立的编程话题,包括算法优化、代码调试、程序设计等,并通过大量的实例和案例讲解了相应的技巧和方法。这些实例涵盖了几乎所有计算机领域,包括排序、查找、字符串处理等,从而帮助读者理解和掌握这些技巧。 与其他编程书籍不同,《编程珠玑》强调的是实用性和深度思考。书中的每个问题都是作者亲自经历过的,每个解决方案都是经过深思熟虑的。通过阅读这本书,读者可以学习到如何通过合理的数据结构和算法设计,将问题简化并高效解决。同时,作者还教会了读者如何思考和分析问题,如何避免一些常见的陷阱和错误。 《编程珠玑》不仅适合初级的程序员,也适合有一定编程经验的开发者阅读。无论是学习编程的初学者,还是已经有多年开发经验的工程师,都可以通过阅读这本书,提升自己的编程能力和思维方式。读者可以在书中找到灵感和启示,解决实际的编程难题,并学到一些通用的编程技巧和原则。 总之,《编程珠玑》是一本极具价值的编程书籍,其内容丰富实用,思想深入,对于提升编程能力和思维方式都具有重要意义。无论是想成为一名优秀的程序员,还是找到解决实际问题的思路,这本书都值得一读。 ### 回答2: 《编程珠玑》是由Jon Bentley于1986年出版的一本经典计算机科学书籍。书中主要讨论了各种编程问题和解决方案,旨在帮助读者提高编程技巧和思维能力。 这本书是由编程问题组成的,每个问题都来自实际编程中的实际情况。每个问题都是用C语言描述并解决的。在解决问题的过程中,书中提出了一些有趣的技巧和方法,例如位操作、动态规划、递归和分治等。这些技巧和方法不仅可以帮助我们解决具体的问题,还可以帮助我们提高编程效率和代码质量。 《编程珠玑》的作者Jon Bentley是一位计算机科学家,他在书中分享了他多年来在编程领域的经验和见解。通过这本书,读者可以学到很多关于编程的技巧和思维方式,有助于提高解决实际编程问题的能力。 总的来说,《编程珠玑》是一本非常有价值的编程书籍,无论是初学者还是有经验的程序员都可以从中受益。它可以帮助我们了解并掌握解决实际编程问题的方法和技巧,提高我们的编程能力和思维能力。如果你对编程有兴趣,并且想提高自己的编程技术,我强烈推荐你阅读这本书。 ### 回答3: 《编程珠玑》是一本由Jon Bentley编写的计算机科学经典著作,被誉为程序员必读之书。该书探讨了一系列关于编程和算法的知识和技巧,以及一些经典的编程问题和解决方法。 《编程珠玑》的主要目的是通过具体的编程案例和讨论,帮助读者提高编程技巧和解决问题的能力。书中提供了众多的编程小技巧和优化思路,让程序员能够对复杂问题进行有针对性的分析和解决。这些技巧涵盖了各个方面,包括数据结构、算法设计、性能优化等。 该书中的编程珠玑主要包括程序设计的三个重要原则:正确性、性能和可读性。作者通过讲述自己的实践经验,以及一些经典的编程问题和解决方法,来阐述这些原则。读者可以通过学习和理解这些原则,提高自己的程序设计能力,并编写出更加优秀的代码。 除了传授编程技巧和知识外,该书还强调了问题解决的思维方式。作者通过讲述一些实际问题的解决过程,鼓励读者灵活运用各种方法和工具,来解决复杂的编程难题。这种思维方式对于程序员来说非常重要,可以培养解决问题的能力,提高工作效率。 总的来说,《编程珠玑》是一本经典的计算机科学读物,通过具体的案例和讨论,帮助读者提高编程技巧和解决问题的能力。无论是想提升自己的程序设计能力,还是希望更好地解决编程难题,这本书都是值得一读的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值