CF Round #643 (Div. 2) C. Count Triangles

有人说这套题C比D和E 从过题的人数上来看确实这样  D题很好想 过的人很多 E题大佬说是三分裸题(大佬总能一眼看出)等下就补E

我们来讲讲C题  其实有个很简单的而且细节也很少的方法 当时想了想 被队友叫去搞D了  

主要就是利用前缀和思想(虽然我求的是后缀)

我们知道 在 X<=Y<=Z的情况下 要构成三角形就只有一个限制  那就是 X+Y>Z

我们肯定要从a,b,c,d这几个范围下手 

先枚举最小的那条边

a<=X<=b  从a到b枚举一遍

对于第2条边 我们通过它界定一个范围 我们知道第二条边的最大值是 b 最小值是c

那么 我们得到一个初步的范围 X+b-1,X+c-1 

这是第三条边的一个可行边界范围(我乱说的 不知道怎么说)

大概意思是 对于 X和c 这两条边来说 最大的可行边就是 X+c-1

对于 X和c-1 这两条边来说 最大的可行边就是 X+c-2

...以此类推 对于 X和b 这两条边来说 最大的可行边就是 X+b-1

那么我们进行后缀和的修改 

对于 后缀和数组q 

q[x+b-2]--,q[x+c-1]++;

X+b-2 X+b-1 X+b X+b+1......  X+c-2 X+c-1

 -1         0         0       0               0          1

这样 我们做一遍后缀和 

X+b-2 X+b-1 X+b X+b+1......  X+c-2 X+c-1

 0         1         1       1              1         1

但是这仅仅是把每一种组合的边界标记出来  并没有得到完整的可行边(比如比边界边小一些的)

我们考虑一下  对于 边界是 X+c-1 的组合 是不是所有  c<=k<=X+c-1 的边都是可行解 

也就是说任何小于边界边的边都是可以计入答案的  

那么对于上面的后缀和 只标记出了边界边  我们再做一次后缀和  就可以完美的标记出每条边作为最大边对答案的贡献了

X+b-2    X+b-1      X+b     X+b+1......  X+c-2 X+c-1

c-b+1    c-b+1        c-b       c-b-1             2         1

最后我们只要计算区间 c~d之间的和就行啦

为了方便 我把数组开大了一倍

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
typedef long long ll;
ll q[N];
int main(){
	int a,b,c,d;
	scanf("%d%d%d%d",&a,&b,&c,&d);
	for(int i = a; i <= b; i++){
		int l = i+b-1;
		int r = i+c-1;
		q[l-1]--;
		q[r]++;
	}
	for(int i = N-2; i >= 1; i--) q[i]+=q[i+1];
	for(int i = N-2; i >= 1; i--) q[i]+=q[i+1];
	ll ans = 0;
	for(int i = c; i <= d; i++) ans+=q[i];
	printf("%lld\n",ans);
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/weixin_43824564/article/details/106179194