牛客练习赛115(a,b题解)

文章讲述了Antiamuny学习二分搜索算法并用C/C++、Java和Python实现,然后探讨如何根据给定的区间和循环次数反推是否存在特定x值。同时,还涉及山峰序列的重排问题,计算满足条件的重排方式数量。
摘要由CSDN通过智能技术生成

B、Antiamuny wants to leaern binary search again

链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
 

题目描述

Antiamuny 还在学习二分!所以他又通过不同的语言实现了一个二分的子程序:

C/C++:

int f(int l,int r,int x) { // l <= x <= r
    int cnt = 0;
    while(l <= r) {
        cnt++;
        int mid = (l + r) / 2;
        if (mid == x) break;
        if (mid < x) l = mid + 1;
        else r = mid - 1;
    }
    return cnt;
}

Java:

public static int f(int l,int r,int x) { // l <= x <= r
    int cnt = 0;
    while(l <= r) {
        cnt++;
        int mid = (l + r) / 2;
        if (mid == x) break;
        if (mid < x) l = mid + 1;
        else r = mid - 1;
    }
    return cnt;
}

Python:

def f(l, r, x): # l <= x <= r
    cnt = 0
    while l <= r:
        cnt += 1
        mid = (l + r) // 2
        if mid == x: break
        elif mid < x: l = mid + 1
        else: r = mid - 1
    return cnt


可以发现,上述程序实现了在 [L,R]中寻找 x并且返回了 while 循环的运行次数 cnt。
在第 21 届上海大学程序设计联赛春季赛中,Antiamuny 非常好奇:对于给定的 L, R, x,函数 f(L,R,x)返回的 cnt 是多少。

所有人都帮助 Antiamuny 解决了这个问题!但是现在 Antimauny 有了新的疑惑:

对于给定的L, R, cnt,在范围 [L,R]中是否存在一个 x 使得 f(L,R,x)=cnt。

输入描述:

有多组测试数据,第一行包含一个整数 T (1≤T≤10^5) 表示数据组数。

接下来 T 行,每行包含三个整数 L, R, cnt (1≤L≤R≤10^6,1≤cnt≤20),分别表示函数 f(L,R,x) 的三个参数。

输出描述:

对于每组测试数据,如果存在符合条件的 x,则在一行输出一个整数,如果有多种合法的答案,您可以输出任意一个;如果不存在符合条件的 x,则输出 −1。

示例1

输入

5
3 7 2
6 12 2
2 10 3
6 14 8
5 8 1

输出

6
11
9
-1
6

二、思路

根据f(l,r,x)=cnt反推,先直接控制其循环次数为cnt,在cnt--的情况下:

1.每循环一次 l=mid+1;//变换区间

2.if(l>r) 不符合条件跳出循环,否则 mid=(l+r)/2,继续二分。

3.cnt==0的时候,输出mid,并且跳出循坏

三、代码

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
using namespace std;
const int N=2e5+10;
const int inf=0x3f3f3f3f;
int l,r,cnt;
void solve()
{
	cin>>l>>r>>cnt;
	int mid=(l+r)/2;
	int f=0;
	while(cnt--)
	{
		if(cnt==0)
		{
			f=1;
			cout<<mid<<endl;
			break; 
		}
		l=mid+1;
		if(l>r)
		    break;
		else
		    mid=(l+r)/2;
	}
	if(f==0)
	    cout<<-1<<endl;
}
signed main()
{
    int t;
    cin>>t; 
    while(t--)
    {
       solve();
    }
    return 0;
}

A、Mountain sequence

链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
 

我们定义,当一个序列 a存在一个 jjj 满足:

对于所有的 i满足


ai≤ai+1 (1≤i≤j−1)

ai≥ai+1​ (j≤i≤n−1)

那么我们称这个序列为山峰序列

例如 [1,2,3,2,1][5,4,3,2,1][1,1,3] 是山峰序列

而 [1,3,1,5,5,4],[1,3,1,2]就不是山峰序列

现在 Antiamuny 给你了一个长度为 n 的序列,他想重排这个序列,并且他想知道有多少种方法可以使重排后的序列为山峰序列

两种重排的方法不同当且仅当得到的序列不同,比如对于序列 [1,1,2]只有 [1,1,2],[1,2,1],[2,1,1][ 这三种不同的重排方法。

输入描述:

第一行包含一个整数 T (1≤T≤2×10^5),表示询问组数。

对于每组数据,第一行包含一个整数 n (1≤n≤10^5),表示给定的序列长度。

第二行包含 n 个正整数 ai​ (1≤ai≤10^9),表示给出的序列。

输入数据保证 ∑n≤2×10^5

输出描述:

输出 T 行,每行一个整数,第 i 行表示第 i 个询问的答案。

因为答案可能过大,所以你需要输出答案对于 998244353 的余数。

示例1

输入

3
5
1 2 3 4 5
3
3 3 3
3
1 2 1

输出

16
1
3

二、思路

1.将所有(非最大值出现的次数+1)相乘

2.该数字只出现一次的话,只有放在左边或者右边两种情况,推出该数字出现的次数+1的推论

3.可以先排序,用map记录各个数字出现的次数

4.创建结构体,q[i].x表示该位置上的数字,q[i].cnt表示该数字出现的次数

三、代码

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
using namespace std;
const int N=2e5+10;
const int inf=0x3f3f3f3f;
const int p=998244353;
int n;
int a[N];
struct node
{
	int x,cnt;
}q[N];
void solve()
{
	cin>>n;
	int i,k=0;
    map<int,int>vis;//ps:因为a[i]可能取到1e9,所以只能用map()容器来存储
	for(i=0;i<=n;i++)
    {
        q[i].x=0;
        q[i].cnt=0;
	}
	for(i=1;i<=n;i++)
	{
		cin>>a[i];
		vis[a[i]]++;
	}
	sort(a+1,a+1+n);
   // a[n+1]=0;
	for(i=1;i<=n;i++)
	{
		if(a[i]!=a[i+1])
		{
			k++;
			q[k].x=a[i];
			q[k].cnt=vis[a[i]];
		}
	}
	int ans=1;
	for(i=1;i<=k-1;i++)
	{
		ans=ans*(q[i].cnt+1)%p;
	}
	cout<<ans%p<<endl;
	/*for(i=1;i<=k;i++)
	{
		cout<<"x="<<q[i].x<<" "<<"cnt="<<q[i].cnt<<endl;
	}*/
}
signed main()
{
	IOS;
    int t;
    cin>>t; 
    while(t--)
    {
       solve();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值