洛谷-算法2-2-常见优化技巧3

UVA11572 唯一的雪花 Unique Snowflakes

题目描述

企业家 Emily 有一个很酷的主意:把雪花包起来卖。她发明了一台机器,这台机器可以捕捉飘落的雪花,并把它们一片一片打包进一个包裹里。一旦这个包裹满了,它就会被封上送去发售。

Emily 的公司的口号是"把独特打包起来",为了实现这一诺言,一个包裹里不能有两片一样的雪花。不幸的是,这并不容易做到,因为实际上通过机器的雪花中有很多是相同的。Emily 想知道这样一个不包含两片一样的雪花的包裹最大能有多大,她可以在任何时候启动机器,但是一旦机器启动了,直到包裹被封上为止,所有通过机器的雪花都必须被打包进这个包裹里,当然,包裹可以在任何时候被封上。

输入格式

第一行是测试数据组数 T,对于每一组数据,第一行是通过机器的雪花总数 n(n≤106),下面 n 行每行一个在 [0,109] 内的整数,标记了这片雪花,当两片雪花标记相同时,这两片雪花是一样的。

输出格式

对于每一组数据,输出最大包裹的大小。

显示翻译

题意翻译

输入输出样例

输入 #1复制

复制代码
1
5
1
2
3
2
1

输出 #1复制

复制代码
3

实现代码:

cpp 复制代码
#include<cstdio>
#include<map>
using namespace std;
map<int,int> snow;
int T,n,ans,last,a;
int main()
{
	for(scanf("%d",&T);T--;printf("%d\n",ans))
	{
		snow.clear();
		scanf("%d",&n);
		last=ans=0;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a);
			if(snow[a]>last)last=snow[a];
			printf("%d\n",snow[a]);
			ans=max(ans,i-last);
			snow[a]=i;
		}
	}
	return 0;
}

P4653 [CEOI 2017] Sure Bet

题目描述

现在有 n 个 A 类灯泡和 n 个 B 类灯泡,每个灯泡都有各自的权值。

我们将这些灯泡分为 n 组,每组包含一个来自 A 类的灯泡和一个来自 B 类的灯泡。

你可以从中选取任意个灯泡,每选取一个灯泡需要花费 1 的代价。

在你选取完之后,系统会随机在 A 类和 B 类中选择一个类型,并点亮那一类的所有灯泡。你选取的每个点亮的灯泡会给你带来等于它权值的收益。

最终收益相当于你点亮灯泡获得的总收益 减去你选取灯泡的代价

现在请你合理选取灯泡,以最大化可能的最小最终收益。你只需要求出来这个最终收益即可。

输入格式

第一行一个正整数 n ,表示灯泡的组数。

接下来 n 行每行两个空格隔开的实数 Ai​,Bi​。分别表示属于这组的 A 灯泡和 B 灯泡的权值。输入的实数不会超过四位小数。

输出格式

输出最大化的最小可能收益,请输出到小数点后恰好四位。

输入输出样例

输入 #1复制

复制代码
4
1.4 3.7
1.2 2
1.6 1.4
1.9 1.5

输出 #1复制

复制代码
0.5000

说明/提示

样例解释

最优策略是选择第一组的 B 灯泡和第三组的 A 灯泡和第四组的 A 灯泡:

  • 如果 B 类灯泡被点亮,收益是 3.7−3=0.7。
  • 如果 A 类灯泡被点亮,收益是 1.6+1.9−3=0.5 。

最小可能收益是 0.5。

数据范围

对于所有测试点,有 1.0≤Ai​,Bi​≤1000.0,0≤n≤105。

实现代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

int n;
double A[100001],B[100001],ans;
bool visit[100001][2];

bool cmp(double a,double b)
{return a>b;}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) cin>>A[i]>>B[i];
    sort(A+1,A+n+1,cmp);
    sort(B+1,B+n+1,cmp);
    double a=0.0,b=0.0;
    for(double i=1,j=1;i<=n && j<=n;)
    {
        int x=i,y=j;
        a+=A[x]*double(!visit[x][0]);
        b+=B[y]*double(!visit[y][1]);
        visit[x][0]=visit[y][1]=1;
        ans=max(ans,min(a-i-j,b-i-j));
        if(a>=b) j++;
        if(a<=b) i++;
    }
    printf("%.4lf",ans);
    return 0;
}

P3143 [USACO16OPEN] Diamond Collector S

题目描述

奶牛 Bessie 一直喜欢闪闪发光的物体,她最近在业余时间开始了一项爱好------挖掘钻石!她收集了 N 颗大小各不相同的钻石(N≤5×104),并希望将它们中的一部分放在谷仓里的两个展示柜中展示。

由于 Bessie 希望每个展示柜中的钻石大小相对接近,她决定如果两颗钻石的大小相差超过 K,就不能将它们放在同一个展示柜中(如果两颗钻石的大小相差恰好为 K,则可以将它们一起展示在同一个展示柜中)。给定 K,请帮助 Bessie 确定她可以在两个展示柜中一起展示的最大钻石数量。

输入格式

输入文件的第一行包含 N 和 K(0≤K≤109)。

接下来的 N 行每行包含一个整数,表示一颗钻石的大小。所有钻石的大小均为正数且不超过 109。

输出格式

输出一个正整数,表示 Bessie 可以在两个展示柜中一起展示的最大钻石数量。

显示翻译

题意翻译

输入输出样例

输入 #1复制

复制代码
7 3
10
5
1
12
9
5
14

输出 #1复制

复制代码
5

实现代码:

cpp 复制代码
#include<cstdio>
#include<algorithm>
using namespace std;
int n,k,a[50005],c[50005],r=2,ma,ans;
int main(){
    scanf("%d %d",&n,&k);
	a[n+1]=2100000000;
    for(int i=1;i<=n;++i)
        scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    for(int i=1;i<=n;++i){
        while(a[r]<=a[i]+k)r++;
        c[r]=max(r-i,c[r]);
        ma=max(ma,c[i]);
        ans=max(ans,ma+r-i);
    }
    printf("%d",ans);
    return 0;
}

P7910 [CSP-J 2021] 插入排序

题目描述

插入排序是一种非常常见且简单的排序算法。小 Z 是一名大一的新生,今天 H 老师刚刚在上课的时候讲了插入排序算法。

假设比较两个元素的时间为 O(1),则插入排序可以以 O(n2) 的时间复杂度完成长度为 n 的数组的排序。不妨假设这 n 个数字分别存储在 a1​,a2​,...,an​ 之中,则如下伪代码给出了插入排序算法的一种最简单的实现方式:

这下面是 C/C++ 的示范代码:

复制代码
for (int i = 1; i <= n; i++)
	for (int j = i; j >= 2; j--)
		if (a[j] < a[j-1]) {
			int t = a[j-1];
			a[j-1] = a[j];
			a[j] = t;
		}

这下面是 Pascal 的示范代码:

复制代码
for i:=1 to n do
	for j:=i downto 2 do
		if a[j]<a[j-1] then
			begin
				t:=a[i];
				a[i]:=a[j];
				a[j]:=t;
			end;

为了帮助小 Z 更好的理解插入排序,小 Z 的老师 H 老师留下了这么一道家庭作业:

H 老师给了一个长度为 n 的数组 a,数组下标从 1 开始,并且数组中的所有元素均为非负整数。小 Z 需要支持在数组 a 上的 Q 次操作,操作共两种,参数分别如下:

1 x v:这是第一种操作,会将 a 的第 x 个元素,也就是 ax​ 的值,修改为 v。保证 1≤x≤n,1≤v≤109。注意这种操作会改变数组的元素,修改得到的数组会被保留,也会影响后续的操作

2 x:这是第二种操作,假设 H 老师按照上面的伪代码 对 a 数组进行排序,你需要告诉 H 老师原来 a 的第 x 个元素,也就是 ax​,在排序后的新数组所处的位置。保证 1≤x≤n。注意这种操作不会改变数组的元素,排序后的数组不会被保留,也不会影响后续的操作

H 老师不喜欢过多的修改,所以他保证类型 1 的操作次数不超过 5000。

小 Z 没有学过计算机竞赛,因此小 Z 并不会做这道题。他找到了你来帮助他解决这个问题。

输入格式

第一行,包含两个正整数 n,Q,表示数组长度和操作次数。

第二行,包含 n 个空格分隔的非负整数,其中第 i 个非负整数表示 ai​。

接下来 Q 行,每行 2∼3 个正整数,表示一次操作,操作格式见【题目描述】。

输出格式

对于每一次类型为 2 的询问,输出一行一个正整数表示答案。

输入输出样例

输入 #1复制

复制代码
3 4
3 2 1
2 3
1 3 2
2 2
2 3

输出 #1复制

复制代码
1
1
2

说明/提示

【样例解释 #1】

在修改操作之前,假设 H 老师进行了一次插入排序,则原序列的三个元素在排序结束后所处的位置分别是 3,2,1。

在修改操作之后,假设 H 老师进行了一次插入排序,则原序列的三个元素在排序结束后所处的位置分别是 3,1,2。

注意虽然此时 a2​=a3​,但是我们不能将其视为相同的元素

【样例 #2】

见附件中的 sort/sort2.insort/sort2.ans

该测试点数据范围同测试点 1∼2。

【样例 #3】

见附件中的 sort/sort3.insort/sort3.ans

该测试点数据范围同测试点 3∼7。

【样例 #4】

见附件中的 sort/sort4.insort/sort4.ans

该测试点数据范围同测试点 12∼14。

【数据范围】

对于所有测试数据,满足 1≤n≤8000,1≤Q≤2×105,1≤x≤n,1≤v,ai​≤109。

对于所有测试数据,保证在所有 Q 次操作中,至多有 5000 次操作属于类型一。

各测试点的附加限制及分值如下表所示。

测试点 n≤ Q≤ 特殊性质
1∼4 10 10
5∼9 300 300
10∼13 1500 1500
14∼16 8000 8000 保证所有输入的 ai​,v 互不相同
17∼19 8000 8000
20∼22 8000 2×105 保证所有输入的 ai​,v 互不相同
23∼25 8000 2×105

附件下载

sort.zip19.25KB

实现代码:

cpp 复制代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=8005;
int n,q;
int t[MAXN];
struct node{
	int pre,id;
}a[MAXN];
bool cmp(node x,node y){
	if(x.pre!=y.pre) return x.pre<y.pre;
	return x.id<y.id;
}
int main(){
	scanf("%d%d",&n,&q); 
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i].pre);
		a[i].id=i;
	}
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;i++)
		t[a[i].id]=i;
	for(int i=1;i<=q;i++){
		int opt,x,v;
		scanf("%d",&opt);
		if(opt==1){
			scanf("%d%d",&x,&v);
			a[t[x]].pre=v;
			for(int j=n;j>=2;j--)
				if(cmp(a[j],a[j-1])){
					node kkksc03=a[j];
					a[j]=a[j-1];
					a[j-1]=kkksc03;
				}
			for(int j=2;j<=n;j++)
				if(cmp(a[j],a[j-1])){
					node kkksc03=a[j];
					a[j]=a[j-1];
					a[j-1]=kkksc03;
				}
			for(int i=1;i<=n;i++)
				t[a[i].id]=i;
		}
		else{
			scanf("%d",&x);
			printf("%d\n",t[x]);
		}
	}
	return 0;
}

P1578 [WC2002] 奶牛浴场

题目描述

由于 John 建造了牛场围栏,激起了奶牛的愤怒,奶牛的产奶量急剧减少。为了讨好奶牛,John 决定在牛场中建造一个大型浴场。但是 John 的奶牛有一个奇怪的习惯,每头奶牛都必须在牛场中的一个固定的位置产奶,而奶牛显然不能在浴场中产奶,于是,John 希望所建造的浴场不覆盖这些产奶点。这回,他又要求助于 Clevow 了。你还能帮助 Clevow 吗?

John 的牛场和规划的浴场都是矩形。浴场要完全位于牛场之内,并且浴场的轮廓要与牛场的轮廓平行或者重合。浴场不能覆盖任何产奶点,但是产奶点可以位于浴场的轮廓上。

Clevow 当然希望浴场的面积尽可能大了,所以你的任务就是帮她计算浴场的最大面积。

输入格式

输入文件的第一行包含两个整数 L 和 W,分别表示牛场的长和宽。

文件的第二行包含一个整数 n,表示产奶点的数量。

以下 n 行每行包含两个整数 x 和 y,表示一个产奶点的坐标。

输出格式

输出文件仅一行,包含一个整数 S,表示浴场的最大面积。

输入输出样例

输入 #1复制

复制代码
10 10
4
1 1
9 1
1 9
9 9

输出 #1复制

复制代码
80

说明/提示

对于所有数据,0≤n≤5×103,1≤L,W≤3×104。所有产奶点都位于牛场内,即:0≤x≤L,0≤y≤W。

感谢 @凯瑟琳98 提供了 4 组 hack 数据。

实现代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

int read()
{
	int sum = 0 , f = 1;
	char c = getchar();
	while(c < '0' or c > '9')
	{
		if(c == '-') f = -1;
		c = getchar();
	}
	while(c >= '0' and c <= '9')
	{
		sum = (sum << 1) + (sum << 3) + c - '0';
		c = getchar();
	}
	return sum * f;
}

struct S{
	int x , y;
}s[5010];

bool cmp1(S a , S b)
{
	if(a.x != b.x) return a.x < b.x;
	else return a.y < b.y; 
}

bool cmp2(S a , S b)
{
	if(a.y != b.y) return a.y < b.y;
	else return a.x < b.x ; 
}

int l , w , n , ans; 

int main()
{
    l = read() , w = read() , n = read();   
    for(int i = 1; i <= n; i ++) s[i].x = read() , s[i].y = read();
    s[++ n].x = 0 , s[n].y = 0;
	s[++ n].x = 0 , s[n].y = w;
	s[++ n].x = l , s[n].y = 0;
	s[++ n].x = l , s[n].y = w;
    int x1 , x2 , y1 , y2;
    sort(s + 1 , s + n + 1 , cmp1);
    for(int i = 1; i <= n; i ++)
    {
    	x1 = s[i].x , y1 = 0 , y2 = w;
    	for(int j = i + 1; j <= n; j ++)
    	{
				x2 = s[j].x;
				ans = max(ans , (x2 - x1) * (y2 - y1));
	    		if(s[j].y < s[i].y) y1 = max(y1 , s[j].y);
	    	    else y2 = min(y2 , s[j].y); 
		}
	}
    for(int i = n; i >= 1; i --)
    {
    	x1 = s[i].x , y1 = 0 , y2 = w;
    	for(int j = i - 1; j >= 1; j --)
    	{
	    		x2 = s[j].x;
				ans = max(ans , (x1 - x2) * (y2 - y1));
				if(s[j].y < s[i].y) y1 = max(y1 , s[j].y);
	    	    else y2 = min(y2 , s[j].y); 
		}
	}
	sort(s + 1 , s + n + 1 , cmp2); 
	for(int i = 1; i <= n - 1; i ++)
	{
		ans = max(ans , l * (s[i + 1].y - s[i].y));
	}
	
	printf("%d" , ans);
	return 0;
}
相关推荐
foundbug9992 小时前
MATLAB时频分析工具箱:基于FRFT的信号检测与参数估计
开发语言·matlab
DevilSeagull2 小时前
Rust 方法语法:从定义到实践
开发语言·后端·rust
charlie1145141912 小时前
通用GUI编程技术——图形渲染实战(三十七)——D3D11初始化与SwapChain:从零搭建GPU渲染框架
开发语言·c++·3d·图形渲染
陈天伟教授2 小时前
GPT Image 2-城市海报
开发语言·人工智能·gpt·神经网络
原来是猿2 小时前
线程安全的单例模式
linux·服务器·开发语言·单例模式·策略模式
菜鸟555552 小时前
2025江西省CCPC省赛暨全国邀请赛(南昌)
数据结构·c++·算法·acm·思维·ccpc·xcpc
charlie1145141912 小时前
通用GUI编程技术——图形渲染实战(三十六)——Constant Buffer与数据传递:CPU-GPU通信通道
开发语言·c++·windows·c·图形渲染·win32
paeamecium2 小时前
【PAT甲级真题】- Table Tennis (30)
c++·pat考试·pat
南境十里·墨染春水2 小时前
C++笔记 STL lterator迭代器
开发语言·c++·笔记