CF1993C Light Switches 题解
CF1993C Light Switches 题解
题目大意#
有 盏灯,第 盏灯亮着的时间为 ,其中 为给定常数, 为任意非负偶数。求一个最小的 ,使得在时间 所有灯都是亮着的。
Solve#
令 ,显然所有灯的开关状态以 为周期,所以我们考虑把所有灯的开关状态映射到 ,并求出每个灯映射的偏移量 ,即需要往前推多少个周期才能把开关状态映射到 ,显然有 ,那么映射后,这盏灯开着的区间即为 。
对于答案,取 ,其中 , 为在 时刻为开着的灯的个数, 为在 时刻为开着的灯的偏移量的最大值。
但有一些细节。考虑有一些灯的开关状态在 内可能是 11100011
这样的, 在两边。这时候左边的 的偏移量为 ,右侧的 的偏移量为 。
至于具体怎么维护 和 ,显然可以上数据结构比如线段树,但这里提供一种不用数据结构的方法。
考虑借用扫描线的思想,对于每个 ,将对应区间左端点的 加上 ,右端点的 减去 (相当于差分),遍历 时前缀和统计即可。而对于 ,考虑在区间左端点插入二元组 ,右端点插入二元组 。遍历 时,先操作 上的所有二元组,开一个 set
,若二元组第二维是 ,则将 加入,否则删除。那么 即为 set
的末尾元素。
Code#
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
short f=1;
int x=0;
char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
const int N=2e5+10;
int t,n,k,c[N<<1],ans,m;
struct zzn{int x;bool op;};
vector<zzn>q[N<<1];
multiset<int>s;//注意可能有相等的元素,故需要multiset
signed main()
{
t=read();
while(t--)
{
n=read();k=read();ans=1e18;m=k<<1;
s.clear();
for(int i=0;i<m;i=-~i) c[i]=0,q[i].clear();
for(int i=1,a;i<=n;i=-~i)
{
a=read();
c[a%m]++,q[a%m].push_back({a/m,1});
if(a%m+k<m)
c[a%m+k]--,q[a%m+k].push_back({a/m,0});
else//对应上文中 1 在左右两侧的情况
c[0]++,q[0].push_back({a/m+1,1}),
c[(a%m+k)%m]--,q[(a%m+k)%m].push_back({a/m+1,0});
}
for(int i=0,cnt=0;i<m;i=-~i)
{
cnt+=c[i];
for(zzn j:q[i])
{
if(j.op) s.insert(j.x);
else s.erase(s.find(j.x));//相等的元素只删除一个
}
if(cnt==n) ans=min(ans,i+(*--s.end())*m);
}
if(ans==1e18) puts("-1");
else printf("%lld\n",ans);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探