LeetCode611-转化为桶+集合划分思想+生成函数

CSDN
考虑求出res[i]表示a[x]+a[y]=i,x!=y的下标对(x,y)个数。对res做前缀和,则得a[x]+a[y]<=i,x!=y的下标对(x,y)个数,记为ress。设b[x]表示a数组里等于x的元素个数(即开桶思想)。则ress[i]*b[i]表示最大值等于i且不能构成三角形的三元组个数,显然这是不合法的三元组集合的一个划分。则
a n s = C n 3 − ∑ 1 < = i < = m r e s s [ i ] ∗ b [ i ] ans=C_n^3-\sum_{1<=i<=m}ress[i]*b[i] ans=Cn31<=i<=mress[i]b[i]
m表示a数组的最大值,n表示a数组非0元素个数。

求res是经典的生成函数问题。设b数组表示多项式B,答案与B^2有关。但这还不是答案,它包含了自己与自己组合的情况,并且每个二元组都算了2次。自己与自己组合,用B(x^2)表示,则所求多项式为:
B 2 ( x ) − B ( x 2 ) 2 \frac {B^2(x)-B(x^2)}{2} 2B2(x)B(x2)
用NTT求B^2,则复杂度为O(mlogm)。这里是暴力乘的。

class Solution {
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)
public:
    int triangleNumber(vector<int>& a) {
        int n = 0,m = 0;
        vector<int> b(1005);
        for(int x: a) if(x) n++,b[x]++,m = max(m,x);
        vector<int> res(2*m+5);
        rep(i,0,m) rep(j,0,i) res[i] += b[j]*b[i-j];
        rep(i,0,m) res[2*i] -= b[i];
        rep(i,0,m) res[i] /= 2;
        rep(i,1,m) res[i] += res[i-1];
        int ans = n*(n-1)*(n-2)/6;
        rep(i,0,m) ans -= b[i]*res[i];
        return ans;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值