数糖纸(离散化+差分)

链接:https://ac.nowcoder.com/acm/contest/372/D
来源:牛客网
 

题目描述

可能很多人要吐槽为什么标题不是“救救blabla”了。

怪人PM6喜欢数糖纸,不同的糖纸有不同的颜色,一共有 N 张糖纸,第 i 张糖纸颜色为 Ci ,它们的位置都是固定的。PM6喜欢五彩缤纷的糖纸,所以他不希望有重复的颜色。他有一次机会,可以收集任意一段连续区间内的糖纸。求出PM6最多能收集多少张糖纸。

输入描述:

第一行一个正整数 N ,表示共有 N 张糖纸。
第二行共有 N 个正整数,第 i 个正整数表示第 i 张糖纸的颜色 Ci
对于20%的数据:1<=N<=100
对于40%的数据:1<=N<=1000
对于100%的数据:1<=N<=1e6,0<=Ci<=1e9

输出描述:

一个整数表示PM6最多能收集多少张糖纸。

示例1

输入

复制

5
1 2 2 3 4

输出

复制

3

说明

PM6可以收集第3到第5张的糖纸,共有三张。

先看题解

题解代码:自己理解的代码待补~

//主要不知道怎么与离散化,离散化操作太多了 
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<map>
#include<algorithm>
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define inf (int)1e8
typedef unsigned long long ull;
using namespace std;
ll read(){
    ll x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f*=-1; c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
    return f*x;
}
const int maxn=1e6+50;
struct Num{
    int id;
    int data;
}num[maxn];

bool cmp(const Num&a,const Num&b){
    if(a.data<b.data)return 1;
    return 0;
}
int c[maxn],N,cnt=0,top=0,stk[maxn],ans,max_ans=1,last[maxn];
int l,r;
bool via[maxn];
int main(){
    N=read();
    for(int i=1;i<=N;i++){
        num[i].data=read();
        num[i].id=i;
    }
    
    sort(num+1,num+N+1,cmp);
    num[0].data=-1;
    //离散化值得学习 
    for(int i=1;i<=N;i++){
        if(num[i].data!=num[i-1].data)cnt++;
        c[num[i].id]=cnt;
    }//离散化的操作 
    
    
    //c数组就是离散过的原始数组 
    l=1;r=1;via[c[r]]=1;ans=1;last[c[r]]=r;//last就是c[r]上次出现的位置 
    while(l<=N&&r<N){
        r++;//每次r++而l不变,这大概就是差分 
        if(via[c[r]]==0){
            ans++;//当遍历的数没有出现过,答案加加 
        }
        else {//出现过 last[c[r]]可以知道上次出现的位置,非常妙哦 
            for(int j=l;j<=last[c[r]];j++)via[c[j]]=0;//中间的不能用了 
            l=last[c[r]]+1;//上次的位置也不能用了,直接从上次的位置加1开始 
            ans=r-last[c[r]];
        }
        via[c[r]]=1;
        max_ans=max(max_ans,ans);
        last[c[r]]=r;//更新最新右端点的位置 
    }
    printf("%d\n",max_ans);
    return 0;
}

下面是另一个代码,感觉比上面那个好理解一些

 

 

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
struct node
{
	int v,id;
}a[N];
int n,last[N],c[N],vis[N];
bool cmp(node a,node b)
{
	if(a.v==b.v) return a.id<b.id;
	return a.v<b.v;
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i].v);
		a[i].id=i;
	}
	sort(a+1,a+1+n,cmp);
	int cnt=0;
	a[0].v=-1;
	for(int i=1;i<=n;i++)
	{
		if(a[i].v!=a[i-1].v) cnt++;
		c[a[i].id]=cnt;
	}
	
	int l=1,r=1;
	last[c[r]]=r;
	int ans=1,sum=1;
	while(l<=n&&r<=n)
	{
		r++;
		if(vis[c[r]]==0)
		{
			last[c[r]]=r;
			vis[c[r]]=1;
			continue;
		}
		else
		{
			for(int i=l;i<=last[c[r]];i++) vis[c[i]]=0;
			sum=r-l;
			l=last[c[r]]+1;
			ans=max(ans,sum);
			last[c[r]]=r;
			vis[c[r]]=1;
		}
	}
	//printf("l:%d r:%d\n",l,r); 
	ans=max(ans,r-l);
	cout<<ans<<endl;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长沙大学ccsu_deer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值