codeforces 810 C - Do you want a date?

本文解析了 CodeForces 平台上的题目 810C — Do you want a date? 的解题思路。通过排序并枚举集合中最大值的位置来求所有子集的函数值之和,并进行取模运算。

codeforces 810C - Do you want a date?

题意:

​ 有一个集合,其中有n个数字,这个集合有很多子集,现在规定每一个子集必须至少有两个数字,其中子集中两个数字最大的差值就是这个子集的函数值,现在求出所有子集的函数值的和,需要取模。

思路:

​ 很容易想到枚举集合中最大的值的位置,需要对元素排序,例如在i位置和j位置(i

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 3*1e5 + 10;
typedef long long LL;
const LL mod = 1e9+7;

int n;
LL a[maxn];
LL sum[maxn];
LL two[maxn];

int main()
{
//    freopen("in.txt","r",stdin);

    scanf("%d",&n);
    two[0] = 1;
    for(int i = 1;i <= n; i++) {
        two[i] = two[i-1]*2%mod;
    }
    for(int i = 1;i <= n; i++) {
        scanf("%I64d",&a[i]);
    }
    sort(a+1,a+1+n);
    for(int i = 1;i <= n; i++) {
        sum[i] = (a[i] + sum[i-1])%mod;
    }
    LL ans = 0;
    for(int i = 0;i <= n-2; i++) {
        LL temp = (sum[n]-sum[i+1]-sum[n-i-1]);
        temp %= mod;
        if(temp < 0) {
            temp += mod;
        }
        ans = (ans + two[i]*temp%mod)%mod;
    }
    printf("%I64d\n",ans);

    return 0;
}
<think> 我们有一个恒温器,可以在范围 [l, r] 内设置温度。初始温度为 a,我们希望将其调整为 b。每次操作可以任意设置温度,但要求新温度与当前温度的差的绝对值至少为 x(即 |新温度 - 当前温度| ≥ x)。我们需要计算从 a 调整到 b 的最小操作次数。 根据问题,我们可以分情况讨论: 1. 如果 a 等于 b,那么不需要操作,答案为 0。 2. 如果 |a - b| ≥ x,那么我们可以直接一步从 a 调整到 b。 3. 如果上述两种情况都不满足,即 a≠b 且 |a-b|<x,那么我们不能直接一步调整到b,需要借助一个中间温度 c(可能不止一步): - 考虑使用两个边界点 l 和 r 作为中间点。因为题目要求每次改变量至少为x,所以中间点必须满足: (i) 从 a 到 c 的变换:|a-c|≥x (ii) 从 c 到 b 的变换:|c-b|≥x 那么我们可以分两种情况考虑中间点: a. 如果存在一个中间点 c(例如 l 或 r)满足上述两个条件,则我们可以用两步完成:a→c→b。 具体检查: - 如果 |a-l|≥x 且 |b-l|≥x,则可以通过 l 作为中间点,两步完成。 - 如果 |a-r|≥x 且 |b-r|≥x,则可以通过 r 作为中间点,两步完成。 4. 如果上述两步操作的条件也不满足,我们是否就无解呢?不一定,我们还可以考虑三步操作: a → 某个边界点 → 另一个边界点 → b 即:先从一个边界点跳到另一个边界点,然后再到b。注意,这里可能需要三步。但前提是这些步骤都满足每次变化量至少为x。 具体三步操作的条件是: - 如果存在一条路径:a → l → r → b 或 a → r → l → b,并且每一步都满足变化量≥x。 - 实际上,我们不需要显式检查三步操作的所有条件,因为当两步操作条件不满足时,我们可以尝试三步操作。 但是注意,题目中还有一种情况是无解:如果 a 和 b 都不能直接或间接地通过中间点到达,则输出-1。 然而,观察题目引用的代码,其逻辑如下: 1. 如果a==b,输出0。 2. 如果 (a既不能到达左边界也不能到达右边界) 或者 (b既不能到达左边界也不能到达右边界) 则输出-1。 解释:因为如果a不能到达任何一个边界(即|a-l|<x 且 |a-r|<x),那么a无法进行任何操作(因为操作要求变化量≥x,但a到两个边界的变化量都不够,所以无法移动)。同样,如果b不能从任何一个边界到达(即|b-l|<x 且 |b-r|<x),那么我们也无法到达b。 3. 否则,即存在解: - 如果 |a-b|>=x,输出1。 - 否则,如果存在一个边界点(l或r)使得a可以到达该边界点并且该边界点可以到达b(即满足两个条件:|a-边界|>=x 且 |b-边界|>=x),那么输出2。 - 否则,输出3。 注意:为什么三步操作总是可行?因为当上一步条件不满足时,我们可以这样操作: 第一步:a → l(如果|a-l|>=x)或 a → r(如果|a-r|>=x)——注意我们在前面已经排除了a不能到达任何边界的情况,所以a至少能到达一个边界。 第二步:从第一步到达的边界(假设是l)跳到另一个边界r(注意,这里要求|l-r|>=x,因为从l到r的变化量必须>=x,而题目中l和r满足l<=r,且题目没有直接给出l和r的大小关系,但注意题目中l和r是给定的范围,且x>0,那么|l-r|>=x是否一定成立?不一定,但注意题目中的约束:x<=r-l,所以有r-l>=x,因此|r-l|>=x是已知条件。所以从l到r(或从r到l)一定是满足变化量要求的。 第三步:从r(或l)跳到b(注意,我们在前面已经排除了b不能到达任何边界的情况,所以b一定至少与一个边界满足|b-边界|>=x。但是注意,第二步后我们在l或r,如果第二步后我们在l,而b不能从l直接到达(即|b-l|<x),那么我们就需要从l跳到r(因为|l-r|>=x,所以这一步可行),然后再从r到b(因为b至少与一个边界满足条件,所以如果b不能从l到达,那么一定能从r到达?不一定,因为可能b既不能从l直接到达也不能从r直接到达?但前面我们已经排除了b不能到达任何边界的情况吗?注意,我们排除了b既不能到l也不能到r的情况,所以b至少可以与l或r中的一个满足条件。所以第三步我们可以选择那个满足条件的边界到达b。 然而,这里有一个细节:我们第二步后可能在l或r,那么第三步我们只需要从当前边界直接到b,而这个边界必须满足|当前边界-b|>=x?但是注意,我们第二步后有两个边界可以选择(因为第二步就是从边界跳到另一个边界,所以我们可以选择在任意边界结束)。那么实际上,我们可以在第二步后选择那个与b满足条件的边界,然后第三步直接跳到b。 因此三步操作总是可行的吗?是的,因为: 第一步:a -> 边界1(假设为l) 第二步:l -> r (因为|r-l|>=x,可行) 第三步:r -> b (因为b至少与l或r中的一个满足条件,而这里我们选择了r,所以需要b与r满足条件?但是注意,我们第二步后也可以在r,那么第三步需要|r-b|>=x。如果b与r满足条件,那么直接跳;如果b与r不满足条件(即|b-r|<x),那么b一定与l满足条件(因为前面排除了b不能到达任何边界的情况,所以b至少与一个边界满足条件,而这里b与r不满足,则一定与l满足条件)。那么我们就可以在第二步选择从l跳到r后,再跳回l?然后从l到b?这样就成了四步?所以我们需要重新考虑。 实际上,三步操作可以这样设计: 方案1:a -> l -> r -> b (要求:|a-l|>=x, |l-r|>=x(题目条件r-l>=x满足),|r-b|>=x) 方案2:a -> r -> l -> b (要求:|a-r|>=x, |r-l|>=x, |l-b|>=x) 那么三步操作的条件是:存在一条路径,使得方案1或方案2中的三个条件都满足。 但是注意,我们之前只保证了: a至少能到达一个边界(假设能到l,或者能到r,或者都能到), b至少能从一个边界到达(同样,可能是l或r或两者), 且|l-r|>=x(题目条件)。 那么,如果a只能到达l,而b只能到达r,那么我们可以走:a->l->r->b(三步),因为: |a-l|>=x(已知a能到l), |l-r|>=x(题目条件), |r-b|>=x(因为b能到r,即|b-r|>=x,和|r-b|一样)。 同样,如果a只能到达r,而b只能到达l,那么我们可以走:a->r->l->b(三步)。 但是,如果a能到达l和r,而b只能到达l,那么我们可以选择: 方案1:a->r->l->b (要求:|a-r|>=x, |r-l|>=x, |l-b|>=x)—— 其中|l-b|>=x就是b能到达l的条件,满足。 方案2:a->l->b (两步)—— 但是这种情况在两步操作的条件判断中已经被排除了吗?注意两步操作的条件是:存在一个边界点使得a和b都能通过这个边界点连接(即同一个边界点同时满足a到边界和边界到b)。这里如果我们用l作为边界点:a->l->b,需要|a-l|>=x且|b-l|>=x(注意,这里b能到达l即|b-l|>=x,而a能到达l也满足),所以这种情况在两步操作中就应该被判断出来,输出2。所以不会进入三步操作。 因此,三步操作是在两步操作条件不满足的情况下才使用。那么两步操作条件不满足意味着什么? 意味着:不存在一个边界点同时满足a到该边界点变化量>=x且该边界点到b变化量>=x。 即:对于l:|a-l|>=x和|b-l|>=x不能同时成立;对于r:|a-r|>=x和|b-r|>=x不能同时成立。 那么三步操作的条件就是:存在一个边界点,使得a能到达它,同时存在另一个边界点(因为总共有两个边界点),使得b能到达另一个边界点。注意,这两个边界点可能是同一个吗?如果是同一个,那么就是两步操作的情况。所以三步操作的条件是两个边界点分别被a和b使用。 因此,三步操作的条件实际上总是满足的?因为: a至少能到达一个边界(设为边界A),b至少能到达一个边界(设为边界B)。如果边界A和边界B是同一个,那么两步操作条件满足(我们就会输出2)。如果边界A和边界B不是同一个,那么边界只有两个(l和r),所以一个为l,一个为r。那么我们就可以通过三步操作:a->边界A->边界B->b(注意边界A和边界B之间的变化量是满足的,因为|边界A-边界B|=|l-r|>=x)。但是,这里要求从边界A到边界B的变化量>=x,而题目条件保证了这一点(因为x<=r-l,所以|l-r|>=x)。所以三步操作总是可行的吗? 但是,这里有一个问题:三步操作要求从边界A到边界B的变化量>=x,而题目条件确实满足,所以只要a能到达边界A,b能到达边界B,且边界A和边界B不同,那么就可以三步操作。 然而,还有一种情况:边界A和边界B可能是同一个?但我们已经排除了两步操作(即边界A和边界B相同且满足条件的情况),所以剩下的情况就是边界A和边界B不同,那么三步操作可行。 因此,算法总结如下: 1. 如果 a == b,输出0。 2. 如果 a 无法到达 l 且 a 无法到达 r(即|a-l|<x 且 |a-r|<x),则无解,输出-1。 3. 如果 b 无法到达 l 且 b 无法到达 r(即|b-l|<x 且 |b-r|<x),则无解,输出-1。 4. 如果 |a-b|>=x,输出1。 5. 否则,检查是否存在一个边界点(l或r)使得同时满足: |a-边界点|>=x 且 |b-边界点|>=x 如果存在,输出2。 6. 否则,输出3。 注意:第5步的检查包括两个边界点: 边界点为l:|a-l|>=x 且 |b-l|>=x 边界点为r:|a-r|>=x 且 |b-r|>=x 为什么这样是正确的?因为如果存在一个边界点(比如l)同时满足a和b都能以一步操作到达(变化量>=x),那么我们可以用两步:a->l->b。同理r也一样。 而如果不存在这样的边界点,那么说明: - 对于l:要么a不能到达l,要么b不能到达l(或者两者都不能,但至少有一个不能,因为如果两个都能,我们就输出2了)。 - 对于r:同样,要么a不能到达r,要么b不能到达r(或者两者都不能)。 但是注意,我们在第2步和第3步已经保证了a至少能到达一个边界,b也至少能到达一个边界。那么,a能到达的边界和b能到达的边界一定是不同的两个边界(因为如果相同,那么那个边界就同时满足a和b都能到达,那么第5步就会输出2)。因此,a只能到达一个边界(比如l)而b只能到达另一个边界(比如r),或者a两个边界都能到达而b只能到达其中一个(但此时如果a能到达的边界和b能到达的边界有交集,则两步操作条件满足,所以不会进入第6步;如果没有交集,即b只能到达a不能到达的那个边界,那么a只能到达l,b只能到达r,那么就需要三步操作:a->l->r->b)。同理,a只能到达一个边界(比如r)而b只能到达另一个边界(比如l)的情况也一样。 所以三步操作的条件就是:a和b能到达的边界集合不相交(即没有共同的边界点)。而由于边界只有两个,那么必然是一个边界被a独占,另一个边界被b独占。这样就需要三步操作。 但是还有一种情况:a能到达两个边界,而b只能到达一个边界(比如r),并且这个边界r与a的关系满足:|a-r|>=x(a能到达r),但是b不能到达l(所以b只能到达r)。那么,我们能否用两步操作?即a->r->b:第一步a->r(满足|a-r|>=x),第二步r->b(需要|r-b|>=x,而这里b能到达r,即|b-r|>=x,所以满足)。那么这种情况应该输出2。但是根据第5步的检查,我们检查边界点r:|a-r|>=x(满足)且|b-r|>=x(满足),所以就会输出2。 所以,三步操作的条件实际上只有在a和b能到达的边界集合不相交且没有共同边界的情况下才会触发。而由于边界只有两个,那么当且仅当: - a只能到达l,而b只能到达r(或者a只能到达r,而b只能到达l)时,我们才需要三步操作。 因此,算法是正确的。 现在我们用代码实现这个逻辑: 输入:多组测试数据。每组测试数据输入 l, r, x, a, b。 步骤: 1. 如果 a == b,输出0。 2. 如果 (|a-l|<x 且 |a-r|<x) 或者 (|b-l|<x 且 |b-r|<x),则输出-1。 3. 否则,如果 |a-b|>=x,输出1。 4. 否则,检查: 如果 (|a-l|>=x 且 |b-l|>=x) 或者 (|a-r|>=x 且 |b-r|>=x),输出2。 5. 否则,输出3。 注意:在第二步中,我们检查的是a不能移动到任何边界或者b不能从任何边界移动到达,那么无解。 下面根据引用[2]的代码,我们也可以看到相同的逻辑。 但是,引用[2]的代码中,第二步的条件是: if((abs(a-l)<x && abs(a-r)<x) || (abs(b-l)<x && abs(b-r)<x)) cout<<"-1"<<endl; 然后,在else分支中: if (abs(a-b)>=x) 输出1 else if ((abs(a-r)>=x && abs(b-r)>=x) || (abs(a-l)>=x && abs(b-l)>=x)) 输出2 else 输出3 因此,我们按照这个逻辑编写代码即可。 但是注意:题目中x可能大于r-l?但是题目有约束:x≤r−l,所以|x|<=r-l,因此两个边界之间的距离至少为x,所以|l-r|>=x是已知的。 因此,我们按照上述情况编写代码。 下面我们用C++代码实现(与引用[2]类似,但我们会添加注释): </think> ### 解决 CodeForces-2167C (Thermostat) 题目的方法 #### 问题分析 给定温度范围 $[l, r]$,初始温度 $a$ 和目标温度 $b$。每次操作可将温度调整为任意值,但要求 **调整前后的温度差绝对值** $\geq x$。求从 $a$ 到 $b$ 的最小操作次数(若无法达成则输出 $-1$)。 #### 关键思路 通过贪心思想分情况讨论,优先尝试操作次数更少的方案: 1. **直接调整(0 或 1 步)** - 若 $a = b$,无需操作,输出 $0$ - 若 $|a - b| \geq x$,可直接一步调整,输出 $1$ 2. **借助边界点调整(2 步)** - 若存在边界点 $c$($c = l$ 或 $c = r$)满足: $|a - c| \geq x$ **且** $|b - c| \geq x$ 则路径 $a \rightarrow c \rightarrow b$ 只需 2 步 3. **双边界点调整(3 步)** - 若上述条件不满足,但 $a$ 和 $b$ 均可到达**不同**边界(如 $a$ 能到 $l$,$b$ 能到 $r$),则路径: $a \rightarrow l \rightarrow r \rightarrow b$ 或 $a \rightarrow r \rightarrow l \rightarrow b$ 需 3 步(利用 $|l - r| \geq x$ 的性质) 4. **无解情况** - $a$ 无法到达任何边界($|a-l|<x$ 且 $|a-r|<x$) - 或 $b$ 无法从任何边界到达($|b-l|<x$ 且 $|b-r|<x$) #### 代码实现 ```cpp #include <bits/stdc++.h> using namespace std; void solve() { int l, r, x, a, b; cin >> l >> r >> x >> a >> b; // 情况1: 已满足条件 if (a == b) { cout << 0 << endl; return; } // 情况4: 无解检查 if ((abs(a - l) < x && abs(a - r) < x) || (abs(b - l) < x && abs(b - r) < x)) { cout << -1 << endl; return; } // 情况1: 直接一步调整 if (abs(a - b) >= x) { cout << 1 << endl; return; } // 情况2: 单边界点两步调整 if ((abs(a - l) >= x && abs(b - l) >= x) || (abs(a - r) >= x && abs(b - r) >= x)) { cout << 2 << endl; return; } // 情况3: 双边界点三步调整 cout << 3 << endl; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) solve(); return 0; } ``` #### 复杂度分析 - **时间复杂度**:$O(1)$ 每组数据(仅需常数次条件判断) - **空间复杂度**:$O(1)$(无额外空间占用) #### 示例说明 | 输入 `l r x a b` | 逻辑分析 | 输出 | |------------------|-----------------------------|------| | `3 5 2 3 5` | $|3-5|=2 \geq 2$ → 1 步 | `1` | | `1 10 4 5 2` | $5 \rightarrow 1 \rightarrow 2$ | `2` | | `1 5 3 2 4` | $2 \rightarrow 5 \rightarrow 1 \rightarrow 4$ | `3` | | `1 2 10 1 2` | $a$ 无法离开 $l$ | `-1` | [^1]: 分情况讨论的核心逻辑参考自 CodeForces 官方题解 [^2]: 代码实现基于比赛提交的通用范式
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值