2019ICPC南京网络赛G题 Quadrilateral

给定四边形四条边的长度范围,求所有可能的四边形数量。题目涉及数据范围、枚举与容斥原理,解题关键在于边长限制条件的转化与计数方法。
摘要由CSDN通过智能技术生成
题意:

给定四边形的四条边,每条边si∈[s1,s2],求能形成的四边形总数

数据范围:

t=1e3,三条边1-1e5,剩下一条1-1e3

链接:

https://nanti.jisuanke.com/t/41304

题解:

设四条边a,b,c,d,枚举d,容斥将边范围化为[1,a1-1],[1,a2]
于是只需考虑范围为[1,Ra]的情况,考虑容斥,总数为RaRbRc,减去每条边分别为最长边&&构不成四边形的情况,因为边长不为0,所以不构成四边形时不会存在两条最长边。
若a为最长边,只需要统计b+c+d≤a,即b+c≤a-d,即[1,Rb]+[1,Rc]≤[1-d,Ra-d],若d为最长边,只需要统计a+b+c≤d,即a+b≤d-c,即[1,Ra]+[1,Rb]≤[d-Rc,d-Rd]
以上两张情况都可以转化为[1,Ra]+[1,Rb]≤[1,Rc]的问题,或其之差
这个问题我们可以画一张表格记数,然后高斯求和即可,细节细节细节!!!
在这里插入图片描述

#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
ll cal1(ll n){
    return n*(n+1)*((n<<1)+1)/6;
}
ll cal2(ll f,ll e,ll l){
    return ((e-f+1)*(e+f)/2)*l;
}
ll cal3(ll f,ll e,ll l){
    if(f>e)return 0;
    return (e-f+1)*l*f+(l-f)*((e-f)*(e-f+1)/2)-cal1(e-f);
}

ll cal4(ll a,ll b,ll c){
    if(a>b)swap(a,b);
    ll ret=0,cnt=0;
    if(c<=a)return cal1(c);
    else{
        ret+=cal1(a);
        if(c<=b){
            return ret+cal2(a+1,c,a);
        }
        else{
            ret+=cal2(a+1,b,a);
            if(c<=a+b-1){
                return ret+cal3(b+1,c,a-1);
            }
            else{
                ret+=cal3(b+1,a+b-1,a-1);
                return ret;
            }
        }
    }
}

ll cal5(ll a,ll b,ll c){
    if(a>b)swap(a,b);
    ll ret=0;
    if(c<=a)return c*(c+1)/2;
    else{
        ret+=a*(a+1)/2;
        if(c<=b){
            return ret+(c-a)*a;
        }
        else{
            ret+=(b-a-1)*a;
            if(c<=a+b-1){
                return ret+(a+a-(c-b))*(c-b+1)/2;
            }
            else{
                ret+=a*(a+1)/2;
                return ret;
            }
        }
    }
}

ll cal6(ll a,ll b,ll c){
    return cal5(a,b,c)*c-cal4(a,b,c);
}

ll cal7(ll a,ll b,ll c,ll d){
    ll ret=a*b*c;
    ret-=cal6(a,b,c-d);
    ret-=cal6(a,c,b-d);
    ret-=cal6(b,c,a-d);
    ret-=(cal6(a,b,d-1)-cal6(a,b,d-c-1));
    return ret;
}

ll cal8(ll a1,ll a2,ll b1,ll b2,ll c1,ll c2,ll d){
    a1--,b1--,c1--;
    return cal7(a2,b2,c2,d)

          -cal7(a1,b2,c2,d)
          -cal7(a2,b1,c2,d)
          -cal7(a2,b2,c1,d)

          +cal7(a2,b1,c1,d)
          +cal7(a1,b2,c1,d)
          +cal7(a1,b1,c2,d)

          -cal7(a1,b1,c1,d);
}

void check(){
    cout<<cal1(2)<<" "<<cal1(3)<<" "<<cal1(4)<<endl;
    cout<<cal2(1,3,1)<<" "<<cal2(2,4,2)<<endl;
    cout<<cal3(5,7,6)<<" "<<cal3(2,4,5)<<endl;
    cout<<endl;
    for(int i=1;i<=15;i++){
        cout<<i<<" "<<cal4(5,9,i)<<" "<<cal4(5,9,i)-cal4(5,9,i-1)<<endl;
        cout<<i<<" "<<cal5(5,9,i)<<" "<<cal5(5,9,i)-cal5(5,9,i-1)<<endl;
    }
    cout<<endl;
    cout<<cal7(1,1,1,1)<<" "<<cal7(2,2,2,2)<<" "<<cal7(3,4,2,3)<<" "<<cal7(3,4,2,1)<<endl;
    cout<<endl;
}

int main(){
    //check();
    int t;cin>>t;
    while(t--){
        int q,w,e,r,t,y,u,i;cin>>q>>w>>e>>r>>t>>y>>u>>i;
        ll ans=0;
        for(int j=u;j<=i;j++){
            ans+=cal8(q,w,e,r,t,y,j);
        }
        cout<<ans<<endl;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值