信奥赛-刷题笔记-二分篇-T2-P1918保龄球0529

总题单

本部分总题单如下

【腾讯文档】副本-CSP-JS+NOI 题单 (未完待续)

https://docs.qq.com/sheet/DSmJuVXR4RUNVWWhW?tab=BB08J2

二分篇题单

请在此添加图片描述

P1918 保龄球

https://www.luogu.com.cn/problem/P1918

题目描述

DL 算缘分算得很烦闷,所以常常到体育馆去打保龄球解闷。因为他保龄球已经打了几十年了,所以技术上不成问题,于是他就想玩点新花招。

DL 的视力真的很不错,竟然能够数清楚在他前方十米左右每个位置的瓶子的数量。他突然发现这是一个炫耀自己好视力的借口——他看清远方瓶子的个数后从某个位置发球,这样就能打倒一定数量的瓶子。

  1. ◯ ◯ ◯ \bigcirc \bigcirc \bigcirc

  2. ◯ ◯ ◯   ◯ \bigcirc \bigcirc \bigcirc\ \bigcirc  

  3. ◯ \bigcirc

  4. ◯   ◯ \bigcirc\ \bigcirc  

如上图,每个 “ ◯ \bigcirc ” 代表一个瓶子。如果 DL 想要打倒 3 3 3 个瓶子就在 1 1 1 位置发球,想要打倒 4 4 4 个瓶子就在 2 2 2 位置发球。

现在他想要打倒 m m m 个瓶子。他告诉你每个位置的瓶子数,请你给他一个发球位置。

输入格式

第一行包含一个正整数 n n n,表示位置数。

第二行包含 n n n 个正整数 a i a_i ai ,表示第 i i i 个位置的瓶子数,保证各个位置的瓶子数不同。

第三行包含一个正整数 Q Q Q,表示 DL 发球的次数。

第四行至文件末尾,每行包含一个正整数 m m m,表示 DL 需要打倒 m m m 个瓶子。

输出格式

Q Q Q 行。每行包含一个整数,第 i i i 行的整数表示 DL 第 i i i 次的发球位置。若无解,则输出 0 0 0

输入输出样例 #1

输入 #1

5
1 2 4 3 5
2
4
7

输出 #1

3
0

说明/提示

【数据范围】

对于 50 % 50\% 50% 的数据, 1 ≤ n , Q ≤ 1000 , 1 ≤ a i , m ≤ 10 5 1 \leq n, Q \leq 1000, 1 \leq a_i, m \leq 10^5 1n,Q1000,1ai,m105

对于 100 % 100\% 100% 的数据, 1 ≤ n , Q ≤ 100000 , 1 ≤ a i , m ≤ 10 9 1 \leq n,Q \leq 100000, 1 \leq a_i, m \leq 10^9 1n,Q100000,1ai,m109

代码1-暴力

#include<bits/stdc++.h>

using namespace std;
int n,q,tempq;
int arr[100010]; 
int arrq[100010]; 
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		scanf("%d",&arr[i]);
	}
//	for(int i=0;i<n;i++){
//		printf("%d ",arr[i]);
//	}
	cin>>q; 
	for(int i=1;i<=q;i++){
		scanf("%d",&arrq[i]);
	}
	 
	for(int i=1;i<=q;i++){
		//		printf("%d",tempq);
		// 哨兵
		bool flag = false; 
		// 循环arr 每次都比较一下,如果相等就输出
		for(int j=1;j<=n;j++){
			if(arrq[i]==arr[j]){
				printf("%d\n",j);
				flag=true;
				break;
			}
		} 
		if(!flag) printf("%d\n",0);
	
	}	
	
	return 0;
}
/*

5
1 2 4 3 5
2
4
7
*/

会得80分

代码2-二分

#include<bits/stdc++.h>

using namespace std;
int n,q,tempq;

// 结构体保存值和初识坐标
struct blq{
	int num;
	int pos;
};

blq arr[100010]; 
int arrq[100010]; 

// 二分查找 
int binary_search(int x){
	int l=1,r=n;
	while(l<=r){
		int mid=(l+r)>>1;
		if(arr[mid].num==x) return arr[mid].pos;
		else if(arr[mid].num<x) l=mid+1;
		else if(arr[mid].num>x) r=mid-1;
	}
	return 0;
	
}

bool cmp(blq b1,blq b2){
	if(b1.num>b2.num) return false;
	else return true;
	
}
 
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		scanf("%d",&arr[i].num);
		arr[i].pos=i;
	}
//	for(int i=0;i<n;i++){
//		printf("%d ",arr[i]);
//	}
	cin>>q; 
	for(int i=1;i<=q;i++){
		scanf("%d",&arrq[i]);
	}
	// 对保龄球进行排序
	sort(arr+1,arr+n+1,cmp);
	 
	for(int i=1;i<=q;i++){
		
		printf("%d\n",binary_search(arrq[i]));
	
	}	
	
	return 0;
}
/*

5
1 2 4 3 5
2
4
7
*/

#include<bits/stdc++.h>

using namespace std;
long long n,m,a,ans;
struct data 
{
	long long h,H;
}N[100005];
bool cmp(data x,data y)
{
	return x.h<y.h;
}
bool pd(long long A,long long l,long long r)
{
	long long mid=(l+r)/2;
	if(N[mid].h==A)
	{
		ans=N[mid].H;
		return true; 
	}
	if(l>r)return false;
	if(A<=N[mid].h)return pd(A,l,mid-1);
	else return pd(A,mid+1,r);
}
int main()
{
	cin>>n;
	for(long long i=1;i<=n;i++)
	{
		cin>>N[i].h;
		N[i].H=i;
	}
	sort(N+1,N+1+n,cmp);
	cin>>m;
	for(long long i=1;i<=m;i++)
	{
		cin>>a;
		if(pd(a,1,n))
		{
			cout<<ans<<endl;
		}
		else cout<<0<<endl;
	}
	return 0;
}

代码3-哈希表

当然可以!下面是对你提供的 C++ 代码进行详细注释头文件引用具体化后的版本。这个程序的功能是:

  • 输入一个整数数组;
  • 对每个查询值,输出它在数组中第一次出现的位置索引(从1开始)
  • 如果该值不在数组中,则输出 0

✅ 完整带注释、具体头文件的版本

#include <cstdio>   // 提供 scanf / printf 等C语言标准输入输出函数
#include <iostream> // 提供 cin / cout 等C++标准输入输出流
#include <unordered_map> // 提供哈希表容器 unordered_map
#include <vector>   // 虽然未使用,但有时用于容器统一管理
using namespace std;

// 全局变量声明
int n, q;                       // n表示数组长度,q表示查询次数
int arr[100010];                // 存储输入的数组元素(下标从1开始)
unordered_map<int, int> pos;    // 哈希表:key为数组中的值,value为其第一次出现的下标位置

int main() {
    // 读取数组长度
    cin >> n;

    // 读取数组内容,并记录每个数字第一次出现的位置
    for (int i = 1; i <= n; i++) {
        scanf("%d", &arr[i]);       // 读取第i个元素

        // 如果当前数值还没有被记录过,就保存它的位置
        if (!pos.count(arr[i])) {
            pos[arr[i]] = i;        // key: 数值,value: 第一次出现的位置
        }
    }

    // 读取查询次数
    cin >> q;

    // 处理每个查询
    for (int i = 0; i < q; i++) {
        int x;
        scanf("%d", &x);            // 读取要查询的数值

        // 在哈希表中查找该数值是否存在
        if (pos.count(x)) {
            printf("%d\n", pos[x]); // 存在:输出其第一次出现的位置
        } else {
            printf("0\n");          // 不存在:输出0
        }
    }

    return 0;
}

🧠 补充说明

为什么使用 unordered_map
  • unordered_map 是基于哈希表实现的关联容器。
  • 查找、插入、删除操作的平均时间复杂度为 O(1)
  • 非常适合用于这种“根据值查位置”的问题。
为什么记录的是“第一次出现”的位置?
  • 因为我们只在第一次遇到某个值时才写入哈希表。
  • 后续重复出现的值不会覆盖已有的位置信息。
时间复杂度分析
步骤时间复杂度
读取并处理数组O(n)
查询处理O(q)
总体O(n + q)

🚀 小技巧优化建议

如果你希望进一步提高性能(特别是在大数据量的情况下),可以加上以下两行代码来加速 IO 操作:

ios::sync_with_stdio(false);
cin.tie(nullptr);

这两个语句会关闭 cincoutscanf/printf 的同步,加快输入输出速度。


如果你还有其他问题,比如想了解底层原理、调试方法、或想把这个程序改成支持多组数据等,也可以继续问我 😊

现场真题注意事项

https://cspoj.com/contest.php?cid=1002Fus5yz4x3EcSJH1Z

注意事项

文件名(程序名和输入输出文件名)必须使用英文小写。(提交必须使用freopen()进行提交)

C/C++ 中函数 main() 的返回值类型必须是 int,程序正常结束时的返回值必须是0。

提交的程序代码文件的放置位置请参考各省的具体要求。

因违反以上三点而出现的错误或问题,申述时一律不予受理。

若无特殊说明,结果的比较方式为全文比较(过滤行末空格及文末回车)。

程序可使用的栈空间内存限制与题目的内存限制一致。

全国统一评测时采用的机器配置为:Inter® Core™ i7-8700K CPU @3.70GHz,内存 32GB。上述时限以此配置为准。

只提供 Linux 格式附加样例文件。

评测在当前最新公布的 NOI Linux 下进行,各语言的编译器版本以此为准

假设输入样例数据存在文件test.in中,输出样例数据存在文件test.out中,

则在CSP、NOI等比赛的代码中,需添加freopen、fclose语句,

内容详见模板代码如下。

#include <bits/stdc++.h>
#include<cstdio>//必须包含cstdio头文件
#include<iostream>
using namespace std;
 
int main(){
	freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);
	
	cout<<"Hello NOI"<<endl;
	
	fclose(stdin);
	fclose(stdout);
	
	return 0;
}

复制

下面为函数的简介,详细可参见 http://www.cplusplus.com/reference/clibrary/cstdio/freopen.html

函数名:freopen

声明:

FILE _freopen( const char_ path, const char _mode, FILE_ stream );

所在文件: stdio.h

参数说明:

path: 文件名,用于存储输入输出的自定义文件名。

mode: 文件打开的模式。和fopen中的模式(如r-只读, w-写)相同。

stream: 一个文件,通常使用标准流文件。

返回值:成功,则返回一个path所指定文件的指针;失败,返回NULL。(一般可以不使用它的返回值)

功能:实现重定向,把预定义的标准流文件定向到由path指定的文件中。标准流文件具体是指stdin、stdout和stderr。其中stdin是标准输入流,默认为键盘;stdout是标准输出流,默认为屏幕;stderr是标准错误流,一般把屏幕设为默认。通过调用freopen,就可以修改标准流文件的默认值,实现重定向。

#include<iostream>
#include<cstdio>
using namespace std;
int main(){
    freopen("7532.in", "r", stdin);
    freopen("7532.out", "w", stdout);
    //原来的代码保持不变
    double a, b, r;
    int k;
    cin >> a >> b;
    k = int(a/b);
    r = a - b * k;
    printf("%g", r);
    //-------------
    fclose(stdin);
    fclose(stdout);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

IT从业者张某某

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

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

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

打赏作者

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

抵扣说明:

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

余额充值