- Gooby 的博客
7月29日每日一题题解
- @ 2025-7-29 14:57:05
7月29日
基础组:P1154 奶牛分厩
题意翻译:找到一个最小的 ,使得对于任意的两个不同的正整数 和 ,都满足 。也就是任何两个数模 都不同余。
由于 的上限很小,所以可以枚举 ,然后 去验证。时间复杂度是 的,会T。
所以我们来解一个同余方程式。
题目要求是求不同余,我们将同余式子变形:
也就是,任意两数之间的差,都不是 的倍数。而且注意到 只有 ,因此我们完全可以先把所有的差值都预处理出来,然后枚举 ,检查是否有差值为 这样的值就行。
bool st[N]; // st[i] = true 表示存在差值为i的数对
for (int k = 1; k <= 1000001; k ++ ) {
bool flag = true;
for (int i = k; i <= 1000000; i += k) {
if (st[i]) {
// 发现有差值为k的倍数的数,所以这个k不满足
flag = false;
break;
}
}
if (flag) {
cout << k << endl;
break;
}
}
注意,这个和埃氏筛的时间复杂度是一致的,所以不会T,可以近似看作
提高组:P1311 [NOIP 2011 提高组] 选择客栈
这是一道计数题,对于这种选数对的计数题,通常可以用双指针或者二分来实现。
具体来说,我们可以枚举其中一个数,然后看另一个数怎么选。通常来说,如果另一个数选择的方式满足单调性,那么就可以用二分或者双指针来实现。
我们再来看这题,也尝试枚举其中一个端点,如下图:

现在枚举固定了其中一个端点 ,它的色调是 ,消费是 ,然后我找到的最近的一个消费小于等于 的点在 处,色调是 。
也就是说,接下来所有色调为 的在 及之后的客栈全部都可以作为另一个端点,所以找出这个方案数,累加到答案中即可。其中找方案数可以用二分来实现。
具体来说,可以对每一种色调的客栈都开一个vector,vector<int> v[N]; 中,v[i] 表示色调为 i 的客栈编号组成的数组。我们在这个数组中二分查找 的数有几个就可以了。
然后我们思考,当 变到 时, 依然是 ,不用走回头路。除非在这之前 的,需要重新枚举。满足双指针的性质。
综上所述,我们可以双指针+二分解决这道题目。时间复杂度 。
:思考 的做法。
做法如下
注意到,对于 `v[i]` 来说,其实每次对它查找,也是具有单调性的,也就是下一次查找到的值的位置一定不会比上次查找到的位置要早。那么根据这一点,我们也可以对每个 `v[i]` 设置一个指针,用 `p[i]` 表示当前查找到色调为 `i` 的客栈的位置,初始值都为 `0` (因为vector中push_back数字的时候,默认0下标开始),然后如果当前不满足就一直往下找就行。
总体来说,每个位置最多会被遍历3次(左指针一次,右指针一次,p[i]一次),所以总的时间复杂度是 $O(N)$ 的。