2024CCPC郑州邀请赛(组队VP)

B. 扫雷 1

面:
T0xel 喜欢玩扫雷,但是他玩的扫雷游戏有名为“地雷探测器”的特殊道具。

具体来说,T0xel 会进行 $ n $轮扫雷。每轮扫雷开始之前,T0xel 会获得 1 枚扫雷币。扫雷币在每轮扫雷结束后不会回收,可以保留至下一轮扫雷。T0xel 知道,在第 $ i $ 轮 $(1 \leq i \leq n) $ 扫雷中,花费\(c_i\)枚扫雷币可以购买一个地雷探测器,清除地图中的一个雷。地雷探测器在一轮扫雷中可以购买任意次。

现在 T0xel 想知道,在这 $ n $ 轮扫雷中最多能购买多少个地雷探测器呢?
输入:
第一行,一个正整数 $ n $ $ (1 \leq n \leq 2 \times 10^5) $,表示扫雷轮数。

第二行,$ n $ 个正整数 $ c_1, c_2, \ldots, c_n $ $ (1 \leq c_i \leq 10^9) $。
输出:
一行,一个非负整数,表示答案。
样例:
1:
6
3 2 5 3 4
——————————
2
2:
5
6 3 3 4 2
——————————
2
3:
5
7 6 5 9 8
——————————
0
思路:
本题由队友编写

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node{
	ll x;
	ll num;
	bool operator < (const node& a)const{
		return x<a.x;
	}
};
priority_queue<node> q;

int main(){
	int n;
	scanf("%d",&n);
	ll cnt=0;
	ll sum=0;
	for(int i=1;i<=n;i++){
		sum++;
		ll x;
		scanf("%lld",&x);
		while(!q.empty()&&x<=q.top().x){
			sum=sum+(q.top().x*q.top().num);
			q.pop();
		}
		ll t=sum/x;
		if(t>0){
			q.push({x,t});
		}
		sum-=t*x;
	}
	while(!q.empty()){
		cnt+=q.top().num;
		q.pop();	
	}
	printf("%lld",cnt);
	return 0;
}

D. 距离之比

题面:
对于 $ \mathbb{R}^2 $ 平面上的两个点 $ P(x_P, y_P) $ 与 $ Q(x_Q, y_Q) $ ,$ PQ $ 之间的曼哈顿距离定义为

$
|PQ|_1 = |x_P - x_Q| + |y_P - y_Q|
$

而 $ PQ $ 之间的欧几里得距离定义为

$
|PQ|_2 = \sqrt{(x_P - x_Q)^2 + (y_P - y_Q)^2}
$

现在给出平面上互不重合的 $ n $ 个点 $ P_1, P_2, \ldots, P_n $ ,请求出

$
\max_{1 \leq i < j \leq n} \frac{|P_i P_j|_1}{|P_i P_j|_2}
$
输入:
第一行,一个正整数 $ T $ $ (1 \leq T \leq 10^5) $,表示数据组数。

对于每组数据:

  • 第一行,一个正整数 $ n $ $ (2 \leq n \leq 2 \times 10^5) $,表示平面上的点数。
  • 接下来 $ n $ 行,每行两个整数 $ x_i, y_i $ $ (-10^9 \leq x_i \leq 10^9, -10^9 \leq y_i \leq 10^9) $,表示点 $ P_i(x_i, y_i) $。

保证对于单个测试点有 \(\sum n \leq 2 \times 10^5\)
输出:
对于每组数据:输出一行,一个实数,表示点对之间曼哈顿距离与欧几里得距离之比的最大值。当你
的答案与标准答案的相对误差或绝对误差不超过$ 10^{−9}$时将视为正确答案。
样例:
2
2
0 0
0 1
3
1 1
2 3
5


1.000000000000
1.371988681140
思路:
道题可以用等式变形得出,当两个点的x绝对差与y绝对差越接近,则题目中要求式子值越大。
但是不能直接取最小的,必须得每个扫描一遍。怎么优化?直接在(-1e9,1e9)做个斜率为1的直线,(-1e9,-1e9)做个斜率为-1的直线。然后对这两个直线取个距离分别排序,然后分别计算两个相邻数的$ \frac{|P_i P_j|_1}{|P_i P_j|_2}$ ,取个最大值即可。千万注意sort不要比较double,这样子会TLE!!!!!!!

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                                    long long
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
//const ll p=rnd()%mod;
ll ksm(ll x, ll y)
{
	ll ans = 1;
	while (y)
	{
		if (y & 1)
		{
			ans = ans % mod * (x % mod) % mod;
		}
		x = x % mod * (x % mod) % mod;
		y >>= 1;
	}
	return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
	if (y == 0)
		return x;
	else
		return gcd(y, x % y);
}
void fio()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}
struct s
{
	ll x,y;
	ll dis1;
	ll dis2;
}p[350000];
bool cmp1(s x, s y)
{
	return x.dis1<y.dis1;
}
bool cmp2(s x, s y)
{
	return x.dis2<y.dis2;
}
int main()
{
	fio();
	ll t;
	cin>>t;
	while(t--)
	{
		ll n;
		cin>>n;
		for(ll i=1;i<=n;i++)
		{
			cin>>p[i].x>>p[i].y;
			p[i].dis1=abs(p[i].x-p[i].y+2e9+2);
			p[i].dis2=abs(p[i].x+p[i].y+2e9+2);
		}
		sort(p+1,p+1+n,cmp1);
	    double ans=0;
		for(ll i=1;i<=n-1;i++)
		{
			double u=(abs(p[i].x-p[i+1].x)+abs(p[i].y-p[i+1].y));
			double ku=fabs(sqrt((p[i].x-p[i+1].x)*(p[i].x-p[i+1].x)+(p[i].y-p[i+1].y)*(p[i].y-p[i+1].y)));
			ans=max(ans,u/ku);
		}
		sort(p+1,p+1+n,cmp2);
		for(ll i=1;i<=n-1;i++)
		{
			double u=(abs(p[i].x-p[i+1].x)+abs(p[i].y-p[i+1].y));
			double ku=fabs(sqrt((p[i].x-p[i+1].x)*(p[i].x-p[i+1].x)+(p[i].y-p[i+1].y)*(p[i].y-p[i+1].y)));
			ans=max(ans,u/ku);
		}
		printf("%.12lf\n",ans);
	}
}

F. 优秀字符串

题面:
小A认为,一个字符串 $S $ 是优秀字符串,当且仅当:

  • $S $ 的长度 $|S| $ 恰好为 5;
  • $ S $ 的第三个字符与第五个字符相同;
  • $ S $ 的前四个字符互不相同。

例如 "henan" 是优秀字符串,但 "query"、"problem"、"queue" 不是,因为:

  • "query" 的第三个字符为 'e',而第五个字符为 'y';
  • "problem" 的长度不为 5;
  • "queue" 的前四个字符中 'u' 出现了两次。

现在,小A有 $ n $ 个仅包含英文字母与数字的字符串 $ S_1, S_2, \ldots, S_n $,请你帮小A求出这些字符串中优秀字符串的数量。
输入:
第一行,一个正整数 $ n $ $ (1 \leq n \leq 10^5) $,表示字符串的数量。

接下来 $n $ 行,每行一个仅包含英文字母与数字的字符串 $ S_i $。保证 $ \sum |S_i| \leq 2 \times 10^5 $。
输出:
一行,一个整数,表示给定字符串中优秀字符串的数量。
样例:
4
henan
query
problem
queue


1
思路:
签到题,首先看size,然后判断地第3个字符和第5个字符是否相等。最后map遍历一遍看有没重复即可

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                                     long long
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
const ll p=rnd()%mod;
ll ksm(ll x, ll y)
{
	ll ans = 1;
	while (y)
	{
		if (y & 1)
		{
			ans = ans % mod * (x % mod) % mod;
		}
		x = x % mod * (x % mod) % mod;
		y >>= 1;
	}
	return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
	if (y == 0)
		return x;
	else
		return gcd(y, x % y);
}
void fio()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}
int main()
{
	fio();
	ll t;
	cin>>t;
	ll ans=0;
	while(t--)
	{
		string f;
		cin>>f;
		if(f.size()==5&&f[2]==f[4])
		{
			map<char,ll>q;
			ll pd=0;
			for(ll i=0;i<=3;i++)
			{
				q[f[i]]++;
				if(q[f[i]]>=2)
				pd=1;
			}
			if(pd==0)
			ans++;
		}
		
	}
	cout<<ans<<endl;
}

H.随机栈

题面:
Toxel获得了一个随机的“栈”。这个栈可被视为一个多重集 $ S $,从一个非空的随机栈 $S $ 中取出一个元素时,有可能从中取出任何一个元素,其中每个元素被取出的概率是相等的。取出该元素后,该元素会从集合中删除。以 \(\{1,2,2\}\) 为例,有 \(\frac{1}{3}\) 的概率取出 1,使得集合变为 \(\{2,2\}\),有 \(\frac{2}{3}\) 的概率取出 2,使得集合变为 \(\{1,2\}\)。每次取出元素的事件相互独立。

Toxel正在对这个集合做一些操作。集合初始时为空,它总共进行了 \(2n\) 次操作,其中 \(n\) 次操作为插入,\(n\) 次操作为取出。现在,Toxel告诉了你它操作的顺序以及每次插入的数,且保证每次取出时,集合非空。Toxel想知道,如果把每次取出的数排成一个序列,那么这个序列递增的概率是多少?这里,递增的严格定义是:取出数列的每一项(除最后一项)小于等于它的后一项。

由于答案可能不是整数,为了方便计算,你只需要求出这个值对 998244353 取模的结果。
输入:
第一行包含一个整数 $ n $ $ (1 \leq n \leq 2 \times 10^9) $。

第二行包含 $ 2n $ 个整数 $ a_1, a_2, \ldots, a_{2n} $ $ (-1 \leq a_i \leq n) $,表示 Toxel 操作的序列。其中,若 $ 0 \leq a_i \leq n $,表示 Toxel 向集合中插入了 $ a_i $;否则 $ a_i = -1 $,表示 Toxel 从集合中取出了一个元素。数据保证取出元素时,集合非空;保证插入和取出操作的次数分别为 $ n $。
输出:
输出一行一个整数,表示答案对 998 244 353 取模的结果。
样例:
1:
2
1 2 -1 -1
————————
499122177
2:
3
1 2 -1 -1 1 -1
————————
0
3:
4
1 -1 2 -1 3 -1 4 -1
————————
1
思路:
队友写的

#include<bits/stdc++.h>
using namespace std;
//60
typedef long long ll;
const int N=1000050;
const ll mod=998244353;

ll qm(ll a,ll x){
	ll ans=1;
	while(x){
		if(x%2){
			ans=(ans%mod)*(a%mod)%mod;
		}
		a=(a%mod)*(a%mod)%mod;
		x/=2;
	}
	return ans%mod;
}
void mul(ll a,ll b,ll& ans){//a/b*ans;
	ans=(ans%mod*a%mod)%mod;
	ll fenmu=qm(b,mod-2);
	ans=(ans%mod*fenmu%mod)%mod;
}
int goal[N];
int a[N];
map<ll,ll>mp;
int main(){
	int n,m=0;
	scanf("%d",&n);
	for(int i=1;i<=2*n;i++){
		scanf("%lld",&a[i]);
		if(a[i]>=0){
			goal[++m]=a[i];
		}
	}
	sort(goal+1,goal+1+n);
	ll ans=1;
	ll cnt=0;//个数
	ll now=0;
	for(int i=1;i<=2*n;i++){
		if(a[i]>=0){
			mp[a[i]]++;
			cnt++;
		}else{
			ll has=mp[(goal[++now])];
			if(has==0){
				ans=0;break;
			}
			mul(has,cnt,ans);
			mp[goal[now]]--;
			cnt--;
		}
		if(ans==0){
			break;
		}
	}
	printf("%lld",ans%mod);
	return 0;
}
/*
2
1 2 -1 -1
3
1 2 2 -1 -1 -1
*/

J. 排列与合数

题面:
小A在2023年河南省CCPC大学生程序设计竞赛的赛场上遇到了一道名为“排列与质数”的题目。与大多数选手一样,小A并没能在赛场上解决这个棘手的题目。比赛结束后,小A想到了一个与之相关的题目:排列与合数,可是小A仍然没有能力解决。这个名为“排列与合数”的题目是这样的:

给定一个有且仅有5位,且各个数位互不相同的十进制正整数 $ n $。你可以重新排列 $ n $ 的各个数位,但需要保证重新排列得到的整数 $ n' $ 没有前导零。请问重新排列数位得到的 $ n' $ 能否为合数?若能为合数,请求出一个满足条件的 $ n' $。

例如,当 $ n = 12345 $ 时,任意排列得到的 $ n' $ 均是合数,因此可以任意取 $ n' $。当 $ n = 13579 $ 时,可以重新排列数位得到合数 $ n' = 97531 = 7 \times 13933 $。

一个正整数是合数,当且仅当它可以分解为两个不小于2的整数的乘积。

现在,小A带着他的题目来到赛场上求助。你能帮助小A解决这个题目吗?
输入:

第一行,一个正整数 \(T (1 \leq T \leq 10^5)\),表示数据组数。

对于每组数据:

  • 一行,一个正整数 \(n (10^4 \leq n < 10^5)\),保证 \(n\) 的各个数位互不相同。
    输出:
    对于每组数据:

输出一行,一个整数。若能重新排列 $n $ 的数位得到合数 $ n' $ 则输出 $ n' $,否则输出 $-1 $。
样例:
5
12345
12345
12345
12345
13579
————————
12345
54321
13524
45123
97531
思路:
先用欧拉筛先把质数筛出来,然后暴枚所有可能,最后判断下是否为合数就行了,注意数大于0才能进行下一层递归

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                                    int
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
const ll p=rnd()%mod;
ll ksm(ll x, ll y)
{
	ll ans = 1;
	while (y)
	{
		if (y & 1)
		{
			ans = ans % mod * (x % mod) % mod;
		}
		x = x % mod * (x % mod) % mod;
		y >>= 1;
	}
	return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
	if (y == 0)
		return x;
	else
		return gcd(y, x % y);
}
void fio()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}
bool st[150000];
bool fk[150000];
ll z[150000];
ll gs=0;
void ola(ll x)
{
	for(ll i=2;i<=x;i++)
	{
		if(!st[i]){
			gs+=1;
			z[gs]=i,fk[i]=1;
		}
		for(ll j=1;z[j]<=x/i;j++)
		{
			st[z[j]*i]=1;
			if(i%z[j]==0)
			break;
		}
	}
}
ll a[150000];
bool vi[15000];
ll ans;
ll pd=0;
void dfs(ll x,ll sd)
{
	if(pd)
	return ;
	if(sd==6)
	{
		if(!fk[x]==1)
		ans=x,pd=1;
		return ;
	}
	for(ll i=1;i<=5;i++)
	{
		if(vi[i]==0)
		{
			vi[i]=1;
			ll u=x*10+a[i];
			if(u>0)
			{
			dfs(u,sd+1);
			}
			if(pd)return;
			vi[i]=0;
		}
	}
	return ;
}
int main()
{
	fio();
	ll t;
	cin>>t;
	ola(100000);
	while(t--)
	{
	pd=0;
	string f;
	cin>>f;
	ans=0;
	for(ll i=1;i<=5;i++)
	{
		a[i]=f[i-1]-'0';
		vi[i]=0;
		ans=ans*10+a[i];
	}
	dfs(0,1);
	if(pd==0)cout<<-1<<endl;
	else 
	cout<<ans<<endl;
	}
	return 0;
}

k.树上问题

题面:
378QAQ有一棵由\(n\)个节点组成的无根树,节点编号从\(1\)\(n\),每个节点有一个正整数点权。

378QAQ认为一个节点是美丽节点,当且仅当该节点作为根时,对于除根节点以外的所有节点,其点权都不小于其父亲节点的点权的 \(\frac{1}{2}\)

请你计算出有多少个节点是美丽节点。
输入:

第一行包含一个正整数 \(t (1 \leq t \leq 10^4)\),表示数据组数。

对于每组数据:

  • 第一行包含一个正整数 \(n (1 \leq n \leq 10^5)\),表示节点数量。
  • 第二行包含 \(n\) 个正整数 \(a_1, a_2, \ldots, a_n (1 \leq a_i \leq 10^6)\),表示编号为 \(i\) 的节点点权。
  • 之后 \(n-1\) 行,每行包含两个正整数 \(u, v (1 \leq u, v \leq n, u \neq v)\),表示无根树中存在一条连接节点 \(u\) 和节点 \(v\) 的边。

保证单个测试点中所有数据的 \(\sum n \leq 10^5\)
输出:
对于每组数据,输出一个非负整数,代表美丽节点的数量。
样例:
3
3
1 2 3
1 2
2 3
5
3 2 2 2 1
1 2
3 1
4 1
1 5
8
699 673 592 276 600 343 369 374
7 6
8 5
4 6
7 1
7 2
1 8
4


3
1
7
思路:
这题为根的转移变化,首先以1为根构建出基本的树结构,然后进行根动态变化就好了,用vis标记表示这个点是否为不符合点,被标记了就是不符合的,然后用cnt统计不符合标记的个数。每次转移储存原状态,并进行状态更新,回溯进行状态还原,这样可以保证树总是以现在这个节点为根.

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                                    int
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
const ll p=rnd()%mod;
ll ksm(ll x, ll y)
{
	ll ans = 1;
	while (y)
	{
		if (y & 1)
		{
			ans = ans % mod * (x % mod) % mod;
		}
		x = x % mod * (x % mod) % mod;
		y >>= 1;
	}
	return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
	if (y == 0)
		return x;
	else
		return gcd(y, x % y);
}
void fio()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}
ll a[250000];
vector<ll>g[260000];
bool vis[250000];
ll cnt=0;
void dfs(ll x,ll fa)
{
	if(a[x]*2<a[fa])
	vis[x]=1,cnt++;
	for(auto j:g[x])
	{
		if(j==fa)continue;
		dfs(j,x);
	}
	return ;
}
ll ans=0;
void df(ll x,ll fa)
{
	ll u=vis[fa],k=vis[x];
	if(x!=1)
	{
		if(k==1)
		cnt--,vis[x]=0;
		if(u==1)
		cnt--,vis[fa]=0;
		if(a[fa]*2<a[x])
		{
			cnt++,vis[fa]=1;
		}
		if(cnt==0)
		ans++;
	}
	for(auto j:g[x])
	{
		if(j==fa)continue;
		df(j,x);
	}
	if(u==0&&vis[fa]==1)
	cnt--,vis[fa]=0;
	if(u==1&&vis[fa]==0)
	cnt++,vis[fa]=1;
	if(k==0&&vis[x]==1)
	cnt--,vis[x]=0;
	if(k==1&&vis[x]==0)
	cnt++,vis[x]=1;
	return ;
}
int main()
{
	
	fio();
	ll t;
	cin>>t;
	while(t--)
	{
		ans=0;
		a[0]=0;
		ll n;
		cin>>n;
		cnt=0;
		for(ll i=1;i<=n;i++)cin>>a[i],g[i].clear(),vis[i]=0;
		for(ll i=1;i<n;i++)
		{
			ll l,r;
			cin>>l>>r;
			g[l].push_back(r);
			swap(l,r);
			g[l].push_back(r);
		}
		dfs(1,0);
		if(cnt==0)
		ans++;
		df(1,0);
		cout<<ans<<endl;
	}
}

L.Toxel 与 PCPC II

题面:
Toxel正在参加 PCPC (Pokémon Center Programming Contest) 比赛。它写的一段代码中有不少bug,正在调试。这份代码总共有 \(n\) 行,而且经验丰富的Toxel已经知道了其中 \(m\) 行代码有bug,并锁定了这 \(m\) 行的具体位置。但是Toxel还需要进行一些调试以了解错误的具体细节并修复它们。

Toxel会进行多次调试。每次调试时,Toxel可以任选一个 \(i\),使得程序从第1行开始,顺序运行完第 \(i\) 行后退出。Toxel可以通过这 \(i\) 行代码运行的一些输出结果来进行debug。运行这 \(i\) 行代码总共需要 \(i\) 秒。接下来,Toxel会一次性地debug这 \(i\) 行代码,并修复所有这 \(i\) 行中的所有bug。bug数量越多,修复所需的时间也越多。设这 \(i\) 行代码中现存的bug数量为 \(x\),那么Toxel需要 \(x^4\) 秒来debug并完成修复。修复后,这 \(i\) 行代码中将不再存在任何bug。

PCPC的赛场争分夺秒。请你帮Toxel计算一下,它最短需要多少秒才能完成debug,修复整个代码中的所有漏洞?
输入:
第一行包含两个整数 ( n, m ) ( (1 \leq m \leq n \leq 2 \times 10^5) )。

第二行包含 ( m ) 个整数 ( a_1, a_2, \ldots, a_m ) ( (1 \leq a_1 < a_2 < \ldots < a_m \leq n) ),表示代码中所有有 bug 的行编号。
输出:
输出一行一个整数,表示答案。
样例:
1:
3 2
1 3
——————
6
2:
1 1
1
——————
2
3:
20 20
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
——————
221
思路:
这题队友写的

#include<bits/stdc++.h>
using namespace std;
//60
typedef long long ll;
const int N=200005;
int n,m;
ll dp[N]={0};
ll a[N]={0};
int main(){
	scanf("%d %d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%lld",&a[i]);		
	}	
	a[0]=a[1];
	for(int i=1;i<=m;i++){
		dp[i]=1e18;
	}
	dp[0]=0;
	for(int i=1;i<=m;i++){
		for(int j=0;i-j>=1&&j<=60;j++){//j个一起
			dp[i]=min(dp[i],dp[i-j-1]+(j+1)*(j+1)*(j+1)*(j+1)+a[i]);
		}
	}
	printf("%lld\n",dp[m]);
	return 0;
}
/*
20 20
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
*/

M.有效算法

题面:
给出长度为 \(n\) 的正整数序列 \(\{a_n\}\)\(\{b_n\}\)。对于每个 \(a_i (1 \leq i \leq n)\),进行恰好一次以下操作:

  • \(a_i\) 变成满足 \(|a_i - x| \leq k \times b_i\) 的任意整数 \(x\)

请你求出最小的非负整数 \(k\),使得存在至少一种方法使得操作后序列 \(\{a_n\}\) 所有数都相等。
输入:
第一行包含一个正整数 \(T (1 \leq T \leq 1.5 \times 10^5)\),表示数据组数。

对于每组数据:

  • 第一行包含一个正整数 \(n (2 \leq n \leq 3 \times 10^5)\)
  • 第二行包含 \(n\) 个正整数 \(a_1, a_2, \ldots, a_n (1 \leq a_i \leq 10^9)\)
  • 第三行包含 \(n\) 个正整数 \(b_1, b_2, \ldots, b_n (1 \leq b_i \leq 10^9)\)

保证单个测试点中所有数据的 \(\sum n \leq 3 \times 10^5\)
输出:
对于每组数据:
输出一行一个整数,表示答案。
样例:
2
4
8 3 3 5
1 2 3 2
5
4 3 4 5 6
3 1 3 1 1
——————
2
2
思路:
显然K越大,答案肯定有,而k越小x的范围越小,所以就去二分k,然后再取算出x的范围,如果x有解r=mid,否则l=mid+1,最后即可得到答案,推荐范围开大点,防止错误

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                                     long long
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
const ll p=rnd()%mod;
ll ksm(ll x, ll y)
{
	ll ans = 1;
	while (y)
	{
		if (y & 1)
		{
			ans = ans % mod * (x % mod) % mod;
		}
		x = x % mod * (x % mod) % mod;
		y >>= 1;
	}
	return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
	if (y == 0)
		return x;
	else
		return gcd(y, x % y);
}
void fio()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}
ll a[550000];
ll b[550000];
int main()
{
	fio();
	ll t;
	cin>>t;
	while(t--)
	{
		ll n;
		cin>>n;
		for(ll i=1;i<=n;i++)cin>>a[i];
		for(ll i=1;i<=n;i++)cin>>b[i];
		ll l=0,r=1e9;
		while(l<r)
		{
			ll z=-2e18,y=2e18;
			ll mid=(l+r)>>1;
			for(ll i=1;i<=n;i++)
			{
				ll u1=-mid*b[i];
				ll u2=mid*b[i];
				z=max(z,a[i]+u1);
				y=min(y,u2+a[i]);
			}
			if(z<=y)
			r=mid;
			else l=mid+1;
		}
		cout<<r<<endl;
	}
}


posted @ 2024-11-30 19:19  长皆  阅读(71)  评论(0)    收藏  举报