1. 程式人生 > >【[CQOI2014]數三角形】

【[CQOI2014]數三角形】

相等 char line 直接 read cout 同一行 () getc

lx讓做的題,其實很簡單,難度評到紫令人吃驚

首先讀進來\(n,m\)\(++\),之後就是一個格點數為\(n*m\)的矩陣了

我們直接求很那做,補集轉化一下,我們容斥來做

首先所有的情況自然是\(C_{n*m}^3\)

再算出不合法的情況

之後有\(m\)列,三個點在同一列上的方案數自然是\(m*C_n^3\)

\(n\)行,三個點在同一行的方案數是\(n*C_m^3\)

最後還有斜線上的情況,由於一條方向向量為\((x,y)\)的直線,當兩個端點在整點上的時候,直線上還有\(gcd(x,y)-1\)個整點,而這樣的的直線一共有\((n-x)(m-y)\)條,這樣只考慮了斜率為正的情況,自然還有斜率為負的情況,顯然兩種情況數量相等,最後還要再乘以二

所以斜線上三點共線的方案數為

\[2*\sum_{i=1}^n\sum_{j=1}^m(gcd(i,j)-1)*(n-i)*(m-j)\]

那麽最後的答案就是

\[C_{n*m}^3-m*C_n^3-n*C_m^3-2*\sum_{i=1}^n\sum_{j=1}^m(gcd(i,j)-1)*(n-i)*(m-j)\]

顯然這都是可以隨便求得,如果\(n,m\)再大一些後面就需要反演啦

代碼

#include<iostream>
#include<cstring>
#include<cstdio>
#define LL long long
#define re register
LL n,m,ans;
inline LL C(LL n,LL m)
{
    LL T=1;
    for(re int i=n;i>=n-m+1;i--) T*=(LL)(i);
    for(re int i=1;i<=m;i++) T/=(LL)(i);
    return T;
}
inline LL read()
{
    char c=getchar();
    LL x=0;
    while(c<‘0‘||c>‘9‘) c=getchar();
    while(c>=‘0‘&&c<=‘9‘)
      x=(x<<3)+(x<<1)+c-48,c=getchar();
    return x;
}
LL gcd(LL a,LL b)
{
    if(!b) return a;
    return gcd(b,a%b);
}
int main()
{
    n=read()+1,m=read()+1;
    ans=C(n*m,3);
    ans-=C(n,3)*m+C(m,3)*n;
    for(re int i=1;i<=n;i++)
    for(re int j=1;j<=m;j++)
        ans-=2ll*(gcd(i,j)-1)*(n-i)*(m-j);
    std::cout<<ans;
    return 0;
}

【[CQOI2014]數三角形】