Pave the Parallelepiped(有重复组合公式+状态压缩)

本文探讨了一道关于将长方体分割成多个小长方体的组合数学问题,通过巧妙的状态压缩与容斥原理,实现了高效的算法解决方案。

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

Pave the Parallelepiped

You are given a rectangular parallelepiped with sides of positive integer lengths A, B and C

.

Find the number of different groups of three integers (a
, b, c) such that 1≤a≤b≤c and parallelepiped A×B×C can be paved with parallelepipeds a×b×c

. Note, that all small parallelepipeds have to be rotated in the same direction.

For example, parallelepiped 1×5×6
can be divided into parallelepipeds 1×3×5, but can not be divided into parallelepipeds 1×2×3

.

Input

The first line contains a single integer t

(1≤t≤105

) — the number of test cases.

Each of the next t
lines contains three integers A, B and C (1≤A,B,C≤105

) — the sizes of the parallelepiped.

Output

For each test case, print the number of different groups of three points that satisfy all given conditions.

Example
Input

4
1 1 1
1 6 1
2 2 2
100 100 100

Output

1
4
4
165

Note

In the first test case, rectangular parallelepiped (1,1,1)

can be only divided into rectangular parallelepiped with sizes (1,1,1)

.

In the second test case, rectangular parallelepiped (1,6,1)
can be divided into rectangular parallelepipeds with sizes (1,1,1), (1,1,2), (1,1,3) and (1,1,6)

.

In the third test case, rectangular parallelepiped (2,2,2)
can be divided into rectangular parallelepipeds with sizes (1,1,1), (1,1,2), (1,2,2) and (2,2,2).

题意:

有一个 A×B×C A × B × C 的长方体,将其分成 a×b×c a × b × c 的小正方体,其中 abc a ≤ b ≤ c 问这样的abc小正方体能有多少种?

分析:

首先我们能够想到的就是abc至少一个是A的因子,一个是B的因子,一个是C的因子。

如果直接用组合数学进行推公式的话,需要考虑的情况太多,细节太多,一般人绝对考虑不全。

我们整体考虑对于a,b,c每个数无非有7中情况,所以我们考虑用三位二进制来表示状态

001 是A的因数
010 是B的因数
011 是A的因数也是B的因数即是gcd(A,B)的因数
100 是C的因数
101 是A的因数也是C的因数即是gcd(A,C)的因数
110 是B的因数也是C的因数即是gcd(B,C)的因数
111 是A的因数也是B的因数也是C的因数即是gcd(A,B,C)的因数

根据题意我们完全可以预处理处最大范围内每个数的因子个数,然后每个样例对于所给的A,B,C
求出gcd(A,B),gcd(A,C),gcd(B,C);
我们便可以利用容斥定理求出7种状态的因子个数cnt[i](i = 1,2,…7)

这样对于a,b,c我们只需要枚举每个数的状态(三重循环),并判断保证三个数至少有一个是A的因子B的因子C的因子,这样我们就得到了满足条件的a,b,c的个数。

1.如果说a,b,c都是不同的状态,那么我们就得到三种数量,从每种数量中选择1个,利用组合数很好求

2.但是如果有两个数或者三个数相同的状态,这就要求我们从一定数量中选择有重复个元素举个例子
如果ab状态相同,都是cnt[s],那么我们应该从cnt[s]中选两个,并且可以重复即a选了k,b也选了k
这就需用到有重复的组合公式:
如果从n个元素中选择r个有重复元素,其公式为:

Crn+r1 C n + r − 1 r

此链接为证明过程

这样对于枚举的一种abc状态,各个数的种类数相乘即可,最后每种abc状态个数相加即为最终答案

是个组合数学好题

code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
ll C(int n,int m){//求组合数
    ll ans = 1;
    for(int i = 1; i <= m; i++){
        ans = ans * (n-i+1) / i;
    }
    return ans;
}
bool check(int a,int b,int c){//保证可以构成大正方形
    if((a & 1) && (b & 2) && (c & 4))
        return true;
    if((a & 1) && (c & 2) && (b & 4))
        return true;
    if((b & 1) && (a & 2) && (c & 4))
        return true;
    if((b & 1) && (c & 2) && (a & 4))
        return true;
    if((c & 1) && (a & 2) && (b & 4))
        return true;
    if((c & 1) && (b & 2) && (a & 4))
        return true;
    return false;
}
int gcd(int a,int b){
    if(b == 0)
        return a;
    return gcd(b,a%b);
}
int cnt[10],use[10];
int fac[maxn];
int main(){
    //预处理因子个数
    for(int i = 1; i < maxn; i++){
        for(int j = i; j < maxn; j += i){
            fac[j]++;
        }
    }
    int t,x,y,z;
    ll ans;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d",&x,&y,&z);
        int xy = gcd(x,y);
        int yz = gcd(y,z);
        int xz = gcd(x,z);
        int xyz = gcd(xy,z);
        //容斥计算出每种状态的因子个数
        cnt[7] = fac[xyz];//111
        cnt[6] = fac[yz] - fac[xyz];//110
        cnt[5] = fac[xz] - fac[xyz];//101
        cnt[4] = fac[z] - fac[xz] - fac[yz] + fac[xyz];//100
        cnt[3] = fac[xy] - fac[xyz];//011
        cnt[2] = fac[y] - fac[xy] - fac[yz] + fac[xyz];//010
        cnt[1] = fac[x] - fac[xy] - fac[xz] + fac[xyz];//001
        ans = 0;
        for(int a = 1; a < 8; a++){
            for(int b = a; b < 8; b++){
                for(int c = b; c < 8; c++){
                    if(check(a,b,c)){
                        memset(use,0,sizeof(use));
                        use[a]++;
                        use[b]++;
                        use[c]++;//标记某种状态出现次数
                        ll tmp = 1;
                        for(int i = 1; i < 8; i++){//有使用重复组合数公式
                            if(use[i])
                                tmp *= C(cnt[i]+use[i]-1,use[i]);
                        }
                        if(tmp > 0)
                            ans += tmp;
                    }
                }
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}
<think>嗯,用户想知道在React项目中什么时候需要使用useRequest进行网络请求,以及它和其他网络请求方式的区别。首先,我需要回忆一下useRequest的功能和特性。根据引用资料,useRequestahooks库中的一个Hook,用于处理网络请求,支持自动请求、轮询、防抖、节流、错误重试、缓存等功能。 用户可能已经在使用其他Hooks,比如useState和useEffect来手动管理请求,或者用过像useAsync这样的库。需要比较useRequest和这些方法的差异。比如,useRequest内置了很多高级功能,而手动处理可能需要编写大量重复代码。 适用场景方面,用户可能遇到需要自动处理加载状态、错误重试或者缓存的情况。比如分页加载、表单提交防抖、实时数据更新等场景。需要明确说明useRequest在这些情况下的优势。 另外,用户提到的其他Hooks如usePagination和useLoadMore,可能需要解释为什么选择useRequest更合适。引用资料指出useRequest整合了这些功能,并且插件化设计使其更灵活。 还要考虑用户可能的困惑点,比如性能优化、如何选择适合的Hook,以及useRequest与swr的异同。需要简明扼要地对比,突出useRequest的集成性和扩展性。 最后,确保回答结构清晰,分点说明适用场景、与其他方式的区别,并引用提供的资料来支持观点。同时,生成的相关问题要贴近实际开发场景,帮助用户进一步理解。</think>### ReactuseRequest 的适用场景及与其他网络请求方式的区别 #### 一、useRequest 的核心适用场景 1. **自动请求管理** 当需要自动触发请求(如页面初始化加载数据)时,useRequest 可通过 `manual: false` 自动执行请求,无需手动调用函数。例如: ```javascript const { data } = useRequest(getUserInfo, { manual: false }); ``` 这比手动组合 `useEffect` + `useState` 更简洁,避免冗余代码[^3]。 2. **高频操作优化(防抖/节流)** 在搜索框输入、表单提交等高频操作场景中,可通过配置 `debounceInterval` 或 `throttleInterval` 减少无效请求。例如: ```javascript const { run } = useRequest(searchKeyword, { debounceInterval: 300 }); ``` 3. **轮询与实时更新** 需定时刷新数据(如监控仪表盘)时,通过 `pollingInterval` 实现轮询请求: ```javascript const { data } = useRequest(fetchLatestData, { pollingInterval: 5000 }); ``` 4. **错误恢复与重试机制** 网络不稳定场景下,`retryCount` 和 `retryInterval` 可自动重试失败请求,提升用户体验。 5. **缓存与性能优化** 支持 `cacheKey` 实现请求结果缓存,避免重复加载相同数据,适用于列表页跳转详情页后返回的场景。 --- #### 二、与其他网络请求方式的对比 | 方式 | 特点 | 局限性 | |---------------------|----------------------------------------------------------------------|---------------------------------------------| | **原生 fetch/axios** | 灵活性强,需手动管理 loading/error 状态 | 需自行封装错误处理、缓存等逻辑 | | **useState + useEffect** | 基础组合,适合简单请求 | 需重复编写 loading/error 逻辑,难以扩展功能 | | **useAsync** | 提供基础异步状态管理(如 loading/data/error) | 缺乏高级功能(如重试、轮询)[^1] | | **usePagination** | 专为分页设计,内置页码管理 | 场景单一,无法复用非分页逻辑 | | **useRequest** | 插件化设计,整合防抖、轮询、缓存等能力,支持自定义扩展 | 学习成本较高,需理解配置项 | --- #### 三、何时优先选择 useRequest? 1. **需要减少样板代码**:自动管理 loading/error 状态,避免重复编写 `try/catch`。 2. **复杂交互场景**:如含防抖的搜索、实时数据仪表盘、表单连续提交拦截。 3. **性能敏感场景**:通过缓存和 SWR(后台重新验证)优化用户体验。 4. **统一请求规范**:团队协作时可通过插件机制封装统一错误处理/日志上报。 ---
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值