Codeforces Round 963 (Div. 2)(补题C,D)

C. Light Switches

原题链接

题意:

房间的灯最初均为关闭状态,安装芯片后,它会每隔k分钟改变一次房间的灯光状态,即会打开灯光k分钟,关闭k分钟再打开,依次重复。
有n个房间,在不同时间安装芯片,最早什么时间可以使这些灯都在打开状态,如果不存在所有房间灯都打开的时刻·,则输出-1.

解题思路:

1.将所有时刻都排序,取最大时刻的亮灯区间
2.依次与数组中别的时刻的亮灯区间取交集
3.取交集时,我们应先将此时刻变换到接近区间的值,然后利用交集更新l,r
4.如果最终交际存在即l<r,则输出最大时刻,否则输出-1

解题代码:

#include <bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 
#define endl '\n'
using namespace std;

void solve() 
{
	int n,k;
	cin>>n>>k;
	int a[n];
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
	}
	sort(a,a+n);
	int l=a[n-1],r=a[n-1]+k-1;
	for(int i=0;i<n-1;i++)
	{
		a[i]=((l-a[i])/(2*k))*(2*k)+a[i];
		if(a[i]+k<l)
		a[i]+=2*k;
		l=max(l,a[i]);
		r=min(r,a[i]+k-1);
	}
	if(l>r)
	{
		cout<<"-1\n";
		return;
	}
	cout<<l<<endl;
}

signed main() {
	IOS
	int T = 1;
	cin >> T;
	while (T--)
	{
		solve();
	}
	return 0;
}

D. Med-imize

原题链接

题意:

给出两个整数n,k以及一个整数数组a,你可以进行操作:任选l,r,但需保证r-l+1=k,可以将下标l-r的元素删除,当a的长度大于k时,必须进行此操作,进行操作后,求出数组a剩余元素的最大可能中值t,(长度为 n 的数组的中值是按非递减顺序对元素进行排序后索引为 ⌊(n+1)/2⌋ 的元素)

解题思路:

这个题是二分+dp

1.由于a的长度大于k时,必须进行操作,因此我们的最终序列长度为m=(n-1)%k+1

2.二分我们需要确定l,r的值,由于mid值这个值在数组a的区间内,因此,我们可以取l为最小值,r为最大值

3.然后就是普通的二分模板

4.dp出现在二分的check函数里,由于最终长度为m,(m=(n-1)%k+1),因此

所有下标在最后的保留的序列中应为j=(i-1)%k+1;

5.我们用数组f记录每次选择的比中值大的数的最大个数

f[j]=max(f[j],f[j-1]+p);//p为记录a[i]是否大于此时选取的中值,如果大于取1,否则取0

6.接下来我们需要看比最大值大的个数有多少个,如果f[m]>=m-(m+1)/2+1,则证明mid值可以取得更大,因此我们可以将l取为中值,否则就证明mid值取得较大,将r取mid-1

7.最终将l=r,输出即可

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t,n,k,m;
int a[500010];
int f[500010];

bool check(int mid)
{
	for(int i=0;i<=m;i++)
	{
		f[i]=0;
	}
	for(int i=1;i<=n;i++)
	{
		int j=(i-1)%k+1;
		int p=0;//p为记录a[i]是否大于此时选取的中值
		if(a[i]>=mid)
		p=1;
		if(j==1)
		f[j]=max(f[j],p);
		else
		f[j]=max(f[j],f[j-1]+p);
	}
	 return (f[m]>=m-(m+1)/2+1);
}

void solve()
{
	cin>>n>>k;
	int l=INT_MAX,r=-1;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		l=min(l,a[i]);
		r=max(r,a[i]);
	}
	l--;r++;
	m=(n-1)%k+1;
	while(l<r)
	{
		int mid=(l+r+1)>>1;
		if(check(mid))
		l=mid;
		else r=mid-1;
	}
	cout<<l<<endl;
}

signed main()
{
    IOS
    int t;
    cin>>t;
    while(t--)
    solve();
    return 0;
}

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值