LintCode 281: Paint the Ceiling (双指针好题)

探讨了在特定条件下,如何利用给定的墙段长度集合来构建面积不超过指定值的房屋,以享受免费天花板涂装服务。通过双指针算法高效地解决了问题,避免了在大规模数据集上的时间限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

281. Paint the Ceiling

You want to build yourself a house. The building company you hired can only build houses with sides from their specific set ss. That means they can build you a square house or a rectangular one but if and only if its length and width belong to the sets.

 

This month, they have a special promotion: they will paint the ceiling of a new house for free... but only if its area is not more than aa. You want them to do it for free but you also want to be sure that the house will be comfortable and not too small. How many possible house configurations can you create to have the ceiling painted for free given the side lengths offered?

 

There is a method to how the company decides what lengths of sides to produce. To determine nn lengths of wall segments to offer, they start with a seed value s​0, some variables k, b and m, and use the following equation to determine all other side lengths s_i:

 

s_i=((k × s_{i-1}+b) mod m+1+s_{i-1}) for 1≤i<n

 

Example

Example 1

 

Input:

s_0 = 2

n = 3

k = 3

b = 3

m = 2

a = 15

Output: 5

Explanation:

For example, you are given s_0=2 and they will produce n=3 total wall lengths. If k=3, b=3 and m=2 we have:

 

s       i    calculation                    result

[2]     1    ((3×2+3)%2)+1+2                 4

[2,4]   2    ((3×4+3)%2)+1+4                 6

[2,4,6]         

Now that we have our set of lengths, we can brute force the solution using the following tests assuming a=15:

 

s=[2,4,6]

​​s1  s2 s1×s2 s1×s2≤a

2   2   4   True

2   4   8   True

2   6   12  True

4   2   8   True

4   4   16  False

4   6   24  False

6   2   12  True

6   4   24  False

6   6   36  False

There are 55 combinations that will result in a free paint job. Brute force will not meet the time constraints on large sets.

 

Notice

1 \leq n \leq 6 × 10^6​​ 

1 \leq s_i \leq 10^9​​ 

1 \leq k,b,m \leq 10^9​​ 

1 \leq a \leq 10^{18}

​​ 

解法1:
双指针法。
1) 注意每次发现可行后,比如说(1,4)可行,那么(1,3), (1,2), (1,1)肯定也可行。然后每个都可以反过来,所以要乘2。但是注意(1,1)算了2次,要减1。

result += 2 * (end - start) + 1;
2) 注意这题跟双指针法有点不一样的地方就是当start==end时,该点可以取2次。所以while(start<=end)而不是while(start<end)。
3) 由此题可以看出双指针法的目标函数不一定是要x+y=c或x-y=c这样的线性函数,非线性xy=c也可以。

class Solution {
public:
    /**
     * @param s0: the number s[0]
     * @param n: the number n
     * @param k: the number k
     * @param b: the number b
     * @param m: the number m
     * @param a: area
     * @return: the way can paint the ceiling
     */
    long long painttheCeiling(int s0, int n, int k, int b, int m, long long a) {
        long long result = 0;
        vector<long long> s(n, 0);
        s[0] = s0;
        
        for (int i = 1; i < n; ++i) {
            s[i] = ((k * s[i - 1] + b) % m) + 1 + s[i - 1];
        }
        
        int start = 0, end = n - 1;
        while(start <= end) {
            if (s[start] * s[end] > a) {
                end--;
            } else {
                result += 2 * (end - start) + 1;
                start++;
            }
        }
        
        return result;
    }
};