题意:
在一张 包含 n
个点 的 完全图 中,自定义其中任意数量的边的方向,所有边的权重都是 1
,要求算出 经过 n
个点,且 每条边只能经过 1
次 的 最短路径 min
和 最长路径 max
。
思路:
观察数据范围,我们发现只能运用 O(logn)
或者 O(1)
的算法,然而前者不方便实现,因此我们考虑用 O(1)
的算法,显然需要找规律。
当 n = 1
时,图上只有 1
个点,显然有 min = max = 0
;
当 n = 2
时,图上只有 2
个点,则 min = max = 1
;
当 n = 3
时,即题中所示样例情况:
min = 2,max = 3
;
在草稿纸上画出接下来的 3
种情况:
当 n = 4
时,
当 n = 5
时,
当 n = 6
时,
当 n = 7
时,
根据上方列出的这 7
种情况,我们在下面一一列出并试着找找规律:
n = 1、2、3、4、 5、 6、 7
min = 0、1、2、3、 4、 5、 6
max = 0、1、3、5、 10、13、21
可以发现,不论 n
为 奇数 还是 偶数,min
的值总是为 n - 1
;
对于 max
:
-
当
n
为 奇数 时,max = n * (n - 1) / 2
; -
当
n
为 偶数 时,max = (n - 1) * (n - 2) / 2 + n / 2
;(在前一奇数项的基础上加上n / 2
)
上面猜测的规律,恰好符合本题正解,严谨的证明过程就不作赘述了(可以了解欧拉图的性质)。
注意,本题需要开 long long。
在比赛的时候,对于找规律的题可以在草稿纸多写写样例,之后就是脑洞大开找规律了,对于本题来说,由于 n
个点的完全图的边数可能太多,画在纸上易出错,我们可以先画 n
个点,之后逐条加边并计数,这样可以一定程度上降低出错率。
时间复杂度:
O(1)
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
int n; cin>>n;
cout<<n-1<<' ';
if(n&1) cout<<n*(n-1)/2<<endl;
else cout<<(n-1)*(n-2)/2+n/2<<endl;
return 0;
}