【[CQOI2014]數三角形】
阿新 • • 發佈:2019-01-02
相等 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]數三角形】