跨年预热关于二分和并查集

二分答案

C. Poisoned Dagger

time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

Monocarp is playing yet another computer game. In this game, his character has to kill a dragon. The battle with the dragon lasts 100500100500 seconds, during which Monocarp attacks the dragon with a poisoned dagger. The ii-th attack is performed at the beginning of the aiai-th second from the battle start. The dagger itself does not deal damage, but it applies a poison effect on the dragon, which deals 11 damage during each of the next kk seconds (starting with the same second when the dragon was stabbed by the dagger). However, if the dragon has already been poisoned, then the dagger updates the poison effect (i.e. cancels the current poison effect and applies a new one).

For example, suppose k=4k=4, and Monocarp stabs the dragon during the seconds 22, 44 and 1010. Then the poison effect is applied at the start of the 22-nd second and deals 11 damage during the 22-nd and 33-rd seconds; then, at the beginning of the 44-th second, the poison effect is reapplied, so it deals exactly 11 damage during the seconds 44, 55, 66 and 77; then, during the 1010-th second, the poison effect is applied again, and it deals 11 damage during the seconds 1010, 1111, 1212 and 1313. In total, the dragon receives 1010 damage.

Monocarp knows that the dragon has hh hit points, and if he deals at least hh damage to the dragon during the battle — he slays the dragon. Monocarp has not decided on the strength of the poison he will use during the battle, so he wants to find the minimum possible value of kk (the number of seconds the poison effect lasts) that is enough to deal at least hh damage to the dragon.

Input

The first line contains a single integer tt (1≤t≤10001≤t≤1000) — the number of test cases.

The first line of the test case contains two integers nn and hh (1≤n≤100;1≤h≤10181≤n≤100;1≤h≤1018) — the number of Monocarp's attacks and the amount of damage that needs to be dealt.

The second line contains nn integers a1a1, a2a2, ..., anan (1≤ai≤109;ai<ai+11≤ai≤109;ai<ai+1), where aiai is the second when the ii-th attack is performed.

Output

For each test case, print a single integer — the minimum value of the parameter kk, such that Monocarp will cause at least hh damage to the dragon.

Example

input

Copy

4
2 5
1 5
3 10
2 4 10
5 3
1 2 4 5 7
4 1000
3 25 64 1337

output

Copy

3
4
1
470

Note

In the first example, for k=3k=3, damage is dealt in seconds [1,2,3,5,6,7][1,2,3,5,6,7].

In the second example, for k=4k=4, damage is dealt in seconds [2,3,4,5,6,7,10,11,12,13][2,3,4,5,6,7,10,11,12,13].

In the third example, for k=1k=1, damage is dealt in seconds [1,2,4,5,7][1,2,4,5,7].

思路:二分算法先将符合条件的筛选出来,再将答案在一个区间里进行二分查找,找出左边界,比它还小的无法完成,所以输出左边界。

(有一种解耦的思想在里面)


//典型二分问法,但二分的是什么?
//t int ,n int ,long long h,ai,
//k 定位longlong型
//ai越没有交集,则越容易使h较小
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N =110;
int n,t;
ll h,a[N];
bool check(ll mid){
	ll ret =0;
	for(int i=2;i<=n;i++){
		if(a[i]-a[i-1]>mid){
			ret+=mid;
		}
		else ret+=a[i]-a[i-1];
	}
	ret+=mid;
	if(ret>=h)
	return true;
	else return false;
}
void solve(){
	cin>>n>>h;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	ll l=1,r=h;
	while(l<r){
		ll mid=(l+r)/2;
		if(check(mid))  r=mid;
		else l=mid+1;
	}
	cout<<l<<endl;
}
int main(){
	int t;
	cin>>t;
	while(t--){
		solve();
	}
	return  0;
}

并查集

Problem Statement

Determine whether there is a way to line up NN people, numbered 11 to NN, in a row side by side to satisfy all of the MM conditions in the following format.

  • Condition: Person A_iAi​ and Person B_iBi​ are adjacent.

Constraints

  • 2 \leq N \leq 10^52≤N≤105
  • 0 \leq M \leq 10^50≤M≤105
  • 1\leq A_i < B_i \leq N1≤Ai​<Bi​≤N
  • All pairs (A_i,B_i)(Ai​,Bi​) are distinct.

Input

Input is given from Standard Input in the following format:

NN MM
A_1A1​ B_1B1​
\vdots⋮
A_MAM​ B_MBM​

Output

If there is a way to line up people to satisfy the conditions, print Yes; if not, print No.

Sample Input 1

4 2
1 3
2 3

Sample Output 1

Yes

One way to satisfy all the conditions is to line them up in the order 4,1,3,24,1,3,2.

Sample Input 2

4 3
1 4
2 4
3 4

Sample Output 2

No

There is no way to line them up to satisfy all the conditions.

Sponsor

思路:题目中需要是一个链状结构,如果是树状或者是环状就不符合要求了

1.这个人和三个及以上的人站一起

2.这个人和a,b站一起,a和b想站一起,呈环状了

 #include <bits/stdc++.h>
 using namespace std;
 const int N=1e5+10;
 int d[N];
 int p[N];
 int find(int x){
 	if(p[x]!=x) p[x]=find(p[x]);
 	return p[x];
 }
 int main(){
 	int n,m;
 	cin>>n>>m;
 	for(int i=1;i<=n;i++) p[i]=i;
 	for(int i=1;i<=m;i++){
	 	int a,b;
	 	cin>>a>>b;
	 	if(find(a)==find(b)){
		 	cout<<"No"<<endl;
		 	return 0;
		 }
		 p[find(a)]=find(b);
		 d[a]++;
		 d[b]++;
	 }
	 for(int i=1;i<=n;i++){
	 	if(d[i]>2){
		 	cout<<"No"<<endl;
		 	return 0;
		 }
	 }
	 cout<<"Yes"<<endl;
	 return 0;
 }


并查集扩展:

题目描述

现有一块大奶酪,它的高度为 hh,它的长度和宽度我们可以认为是无限大的,奶酪中间有许多半径相同的球形空洞。我们可以在这块奶酪中建立空间坐标系,在坐标系中,奶酪的下表面为 z = 0z=0,奶酪的上表面为 z = hz=h。

现在,奶酪的下表面有一只小老鼠 Jerry,它知道奶酪中所有空洞的球心所在的坐标。如果两个空洞相切或是相交,则 Jerry 可以从其中一个空洞跑到另一个空洞,特别地,如果一个空洞与下表面相切或是相交,Jerry 则可以从奶酪下表面跑进空洞;如果一个空洞与上表面相切或是相交,Jerry 则可以从空洞跑到奶酪上表面。

位于奶酪下表面的 Jerry 想知道,在不破坏奶酪的情况下,能否利用已有的空洞跑 到奶酪的上表面去?

空间内两点 P_1(x_1,y_1,z_1)P1​(x1​,y1​,z1​)、P2(x_2,y_2,z_2)P2(x2​,y2​,z2​) 的距离公式如下:

\mathrm{dist}(P_1,P_2)=\sqrt{(x_1-x_2)^2+(y_1-y_2)^2+(z_1-z_2)^2}dist(P1​,P2​)=(x1​−x2​)2+(y1​−y2​)2+(z1​−z2​)2​

输入格式

每个输入文件包含多组数据。

第一行,包含一个正整数 TT,代表该输入文件中所含的数据组数。

接下来是 TT 组数据,每组数据的格式如下: 第一行包含三个正整数 n,h,rn,h,r,两个数之间以一个空格分开,分别代表奶酪中空洞的数量,奶酪的高度和空洞的半径。

接下来的 nn 行,每行包含三个整数 x,y,zx,y,z,两个数之间以一个空格分开,表示空洞球心坐标为 (x,y,z)(x,y,z)。

输出格式

TT 行,分别对应 TT 组数据的答案,如果在第 ii 组数据中,Jerry 能从下表面跑到上表面,则输出 Yes,如果不能,则输出 No

输入输出样例

输入 #1复制

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

输出 #1复制

Yes
No
Yes
//洛谷上的代码,写得很漂亮
#include<bits/stdc++.h>
using namespace std;
int f[1001];
int find(int x){
    if (x!=f[x]) f[x]=find(f[x]);
    return f[x];
}//查找+路径压缩
long long dis(long long x,long long y,long long z,long long x1,long long y1,long long z1){
    return (x-x1)*(x-x1)+(y-y1)*(y-y1)+(z-z1)*(z-z1);
}//两点距离公式,注意这里算的是距离平方。
long long x[100001],y[100001],z[100001];
int f1[100001],f2[100001];
//f1记录与顶面相交的洞的序号
//f2记录与底面相交的洞的序号
int main(){
    int t;
    scanf("%d",&t);
    int n,h; 
    long long r;
    for (int i=1;i<=t;i++){
        scanf("%d%d%lld",&n,&h,&r);//long long不开的话...
        int tot1=0;//记录与顶面相交的洞有几个
        int tot2=0;//记录与底面相交的洞有几个
        for (int j=1;j<=n;j++){
          f[j]=j;  //并查集初始化
         }
        for (int j=1;j<=n;j++){
            scanf("%lld%lld%lld",&x[j],&y[j],&z[j]);//long long不开的话...
            if (z[j]+r>=h){//判断这个点是否与顶面相交
                tot1++;
                f1[tot1]=j;
            }
            if (z[j]-r<=0){//判断这个点是否与底面相交
                tot2++;
                f2[tot2]=j;
            }
            for (int k=1;k<=j;k++){//枚举之前的洞是否与这个洞相交,如果相交则合并集合
            	if ((x[j]-x[k])*(x[j]-x[k])+(y[j]-y[k])*(y[j]-y[k])>4*r*r) continue;
            	//防止爆long long的特判。 
                if (dis(x[j],y[j],z[j],x[k],y[k],z[k])<=4*r*r){
                    int a1=find(j);
                    int a2=find(k);
                    if (a1!=a2) f[a1]=a2;
                }
            }
        }
        int s=0;
        //看看每一个中是否有洞连接上下面
        for (int j=1;j<=tot1;j++){
            for (int k=1;k<=tot2;k++){
                if (find(f1[j])==find(f2[k])){
                    s=1; 
                    break;
                }
            }
            if (s==1) break;
        }
        if (s==1) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    return 0;
} 

总而言之,并查集是将题目给抽象出需要合并的情况,或者用到了并查集分组的思想。

二分

Give you three sequences of numbers A, B, C, then we give you a number X. Now you need to calculate if you can find the three numbers Ai, Bj, Ck, which satisfy the formula Ai+Bj+Ck = X.

Input

There are many cases. Every data case is described as followed: In the first line there are three integers L, N, M, in the second line there are L integers represent the sequence A, in the third line there are N integers represent the sequences B, in the forth line there are M integers represent the sequence C. In the fifth line there is an integer S represents there are S integers X to be calculated. 1<=L, N, M<=500, 1<=S<=1000. all the integers are 32-integers.

Output

For each case, firstly you have to print the case number as the form "Case d:", then for the S queries, you calculate if the formula can be satisfied or not. If satisfied, you print "YES", otherwise print "NO".

Sample Input

3 3 3
1 2 3
1 2 3
1 2 3
3
1
4
10

Sample Output

Case 1:
NO
YES
NO
#include <bits/stdc++.h>
#define MAXN 501
#define LL long long
using namespace std;
LL s[MAXN*MAXN],a[MAXN],b[MAXN],c[MAXN],n1,n2,n3,n,m;

bool erfen(int l,int r,int i,int x)
{
    int mid;
    while(l<=r)
    {
        mid=(l+r)>>1;
        if(s[mid]+c[i]==x) return true;
        if(s[mid]+c[i]>x) r=mid-1;
        else l=mid+1;
    }
    return false;
}
void slove()
{
    int x;
    bool flag;
    while(m--)
    {
        flag=false;
        cin>>x;
        for(int i=1;i<=n3;i++)
          if(erfen(1,n,i,x)){flag=true;printf("YES\n");break;}
        if(!flag) printf("NO\n");
    }
    return ;
}
int main()
{
    int t=0;
    while(~scanf("%d%d%d",&n1,&n2,&n3))
    {
        printf("Case %d:\n",++t);n=0;
        for(int i=1;i<=n1;i++) cin>>c[i];
        for(int i=1;i<=n2;i++) cin>>b[i];
        for(int i=1;i<=n3;i++) cin>>c[i];
        for(int i=1;i<=n1;i++)
          for(int j=1;j<=n2;j++)
            s[++n]=a[i]+b[j];
        sort(s+1,s+n+1);
       cin>>m;
	   slove();
    }
    return 0;
}

Problem Statement

The season for Snuke Festival has come again this year. First of all, Ringo will perform a ritual to summon Snuke. For the ritual, he needs an altar, which consists of three parts, one in each of the three categories: upper, middle and lower.

He has NN parts for each of the three categories. The size of the ii-th upper part is A_iAi​, the size of the ii-th middle part is B_iBi​, and the size of the ii-th lower part is C_iCi​.

To build an altar, the size of the middle part must be strictly greater than that of the upper part, and the size of the lower part must be strictly greater than that of the middle part. On the other hand, any three parts that satisfy these conditions can be combined to form an altar.

How many different altars can Ringo build? Here, two altars are considered different when at least one of the three parts used is different.

Constraints

  • 1 \leq N \leq 10^51≤N≤105
  • 1 \leq A_i \leq 10^9(1\leq i\leq N)1≤Ai​≤109(1≤i≤N)
  • 1 \leq B_i \leq 10^9(1\leq i\leq N)1≤Bi​≤109(1≤i≤N)
  • 1 \leq C_i \leq 10^9(1\leq i\leq N)1≤Ci​≤109(1≤i≤N)
  • All input values are integers.

Input

Input is given from Standard Input in the following format:

NN
A_1A1​ ...... A_NAN​
B_1B1​ ...... B_NBN​
C_1C1​ ...... C_NCN​

Output

Print the number of different altars that Ringo can build.

Sample Input 1

2
1 5
2 4
3 6

Sample Output 1

3

The following three altars can be built:

  • Upper: 11-st part, Middle: 11-st part, Lower: 11-st part
  • Upper: 11-st part, Middle: 11-st part, Lower: 22-nd part
  • Upper: 11-st part, Middle: 22-nd part, Lower: 22-nd part

Sample Input 2

3
1 1 1
2 2 2
3 3 3

Sample Output 2

27

Sample Input 3

6
3 14 159 2 6 53
58 9 79 323 84 6
2643 383 2 79 50 288

Sample Output 3

87

Sponsor


思路:二分查找即可,嘻嘻嘻

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int a[maxn],b[maxn],c[maxn];
int n;
int findls(int key){
	int l=0,r=n-1;
	while(l<=r){
		int mid=(l+r)>>1;
		if(a[mid]>=key) r=mid-1;
		else l=mid+1;
	}
	return r;
}
int findfl(int key){
	int l=0,r=n-1;
	while(l<=r){
		int mid=(l+r)>>1;
		if(c[mid]>key) r=mid-1;
		else l=mid+1;
	}
	return l;
}
int main(){
	cin>>n;
	for(int i=0;i<n;i++) cin>>a[i];
	for(int i=0;i<n;i++) cin>>b[i];
	for(int i=0;i<n;i++) cin>>c[i];
	sort(a,a+n);
	sort(b,b+n);
	sort(c,c+n);
	ll ans=0;
	for(int i=0;i<n;i++){
		ll p1=findls(b[i]);
		ll p2=findfl(b[i]);
		ans+=(p1+1)*(n-p2);
	}
	cout<<ans<<endl;
	return 0;
}

二分题

Every year the cows hold an event featuring a peculiar version of hopscotch that involves carefully jumping from rock to rock in a river. The excitement takes place on a long, straight river with a rock at the start and another rock at the end, L units away from the start (1 ≤ L ≤ 1,000,000,000). Along the river between the starting and ending rocks, N (0 ≤ N ≤ 50,000) more rocks appear, each at an integral distance Di from the start (0 < Di < L).

To play the game, each cow in turn starts at the starting rock and tries to reach the finish at the ending rock, jumping only from rock to rock. Of course, less agile cows never make it to the final rock, ending up instead in the river.

Farmer John is proud of his cows and watches this event each year. But as time goes by, he tires of watching the timid cows of the other farmers limp across the short distances between rocks placed too closely together. He plans to remove several rocks in order to increase the shortest distance a cow will have to jump to reach the end. He knows he cannot remove the starting and ending rocks, but he calculates that he has enough resources to remove up to M rocks (0 ≤ M ≤ N).

FJ wants to know exactly how much he can increase the shortest distance *before* he starts removing the rocks. Help Farmer John determine the greatest possible shortest distance a cow has to jump after removing the optimal set of M rocks.

Input

Line 1: Three space-separated integers: L, N, and M 
Lines 2.. N+1: Each line contains a single integer indicating how far some rock is away from the starting rock. No two rocks share the same position.

Output

Line 1: A single integer that is the maximum of the shortest distance a cow has to jump after removing M rocks

Sample Input

25 5 2
2
14
11
21
17
Sample Output

4
Hint

Before removing any rocks, the shortest jump was a jump of 2 from 0 (the start) to 2. After removing the rocks at 2 and 14, the shortest required jump is a jump of 4 (from 17 to 21 or from 21 to 25).

题意:一头牛在一个湖中央(0点),湖的半径为 l ( l点),从湖中央到岸边之间有一些石块 (xi点),这头牛可以按照顺序踩着石块到岸上。现在主人要扯掉 m 块石块,使得牛必须跳的最小距离 最大。
 

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
ll n,m,l,num[50010];
const ll inf = 9999999999;
ll work(ll l,ll r) //二分枚举
{
    while(l<=r)
    {
        ll mid=(l+r)>>1;
        int ans=0,s=0;
        for(int i=1; i<n; i++)
            if(num[i]-num[s]>=mid)//i -> s 的距离大于 mid 了,所以要更新起点
                s=i;
            else ans++; //删去的石块数
        if(ans>m)  //可以删去石块的数量大于m,说明跳跃距离太大了
            r=mid-1;
        else
            l=mid+1;
    }
    return r;
}
int main()
{
    while(~scanf("%lld%d%d",&l,&n,&m))
    {
        num[0]=0,num[n+1]=l;  //中央 ,岸边
        for(int i=1; i<=n; i++)
            scanf("%lld",&num[i]);
        n+=2;
        sort(num,num+n);  //排序
        ll minn=inf;
        for(int i=1; i<n; i++)
            minn=min(minn,num[i]-num[i-1]);  //最小的跳跃距离
        printf("%lld\n",work(minn,l));
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值