题目分类:思维转换题
思路:题目要求水平向左或向右任意挪动整个羊场的草皮,计算你所能得到的羊毛价值之和的取值有多少种
一个很朴素的思路是:可以先把草皮移到最左边,让最右边草皮的右端点对准第一只羊位置下标,然后不断向右移动草皮,每移动一单位,O(n)遍历每只羊,对羊毛价值求和并存入set中(set初始插入一个0),最后答案为set的大小
但是这个时间复杂度是O(),当w大时显然超时
注意到草皮只有m块,且m*n<=1e5,如果可以把换成m就好了
我们发现,移动草皮会改变绵羊相对于草皮的位置,从而影响其价值。每个绵羊的价值在移动量d的某些临界点发生变化,这些临界点由绵羊的位置和草皮的边界决定。
注意到总价值的变化是由绵羊的临界点引起的。设所有临界点为w-x,即每一个草皮端点与每一只羊下标的差值,在每个临界点,都会有一只绵羊的价值发生变化(一只绵羊从一个草皮移动到另一个草皮),从而导致总价值的改变。
这样,我们可以将总价值看作是一个变量,每次到达一个临界点时,总价值会加上一个变化量(即新草皮的价值减去旧草皮的价值)。
看上去可行,再看看时间复杂度
复杂度在于计算出所有临界点,可以发现,临界点的总个数为n*m(每一个草皮端点与每一只羊下标的差值),所以时间复杂度为O(n*m),刚好满足要求

于是这一题的整体流程
1.算出每一个临界点,以及通过这个临界点时羊毛价值变化量 O(n*m)
2.对于每一个相同的临界点,对其进行价值变化量的合并,并用set统计答案(近似于O(n*m))
3.输出set的大小

**为什么相同偏移量的价值变化量可以合并呢?
原因在于:这些偏移量代表了整个草皮移动过程中的临界点。当移动距离 d 达到某个临界点时,多个绵羊可能会同时切换所在的草皮区间,每个切换都会导致总价值发生变化。这些变化是相互独立的,因此它们的总效果是所有个体变化量的代数和。

代码如下(含注释):
#define int long long
int w[N],v[N],x[N];
set<int>st;

void InfiniteLight() {
    int n,m;
    read(n);
    read(m);
    Forl(i,1,n){
    	read(w[i]);
    	w[i]+=w[i-1];
	}
	Forl(i,1,n){
		read(v[i]);
	}
    Forl(i,1,m){
    	read(x[i]);
	}
	map<int,vector<int>>mp;
    Forl(i,1,m){ //i-th sheep
    	Forr(j,n,0){ //j-th grass
    		int res=v[j+1]-v[j];
    		mp[w[j]-x[i]].push_back(res); //w[j]-x[i]是临界点,当草皮移动距离等于这个值时,羊会从草皮j到草皮j+1,从而引起价值变化 
		}
	}
	st.insert(0); //先插入一个0,表示草皮向左拉无限远时,羊毛总价值为0
	int res=0;
	for(auto i:mp){
		for(auto j:i.second){ //多只羊可能临界点相同,此时总价值的变化等于各只羊变化量的总和,所以要累加 
			res+=j;
		}
		st.insert(res);
	}
    println((int)st.size());
    return ;
}