bzoj3505: [Cqoi2014]数三角形

题目链接

bzoj3505: [Cqoi2014]数三角形

题解

首先n * m的网格图点数为 (n + 1) * (m + 1)
那么n ++,m++
所有的方案\(C(3,n + m)\)减去在同一行的\(m * C(3,n)\)减去在同一列的\(n * C(3,m)\)减去斜着的
枚举两个点,两点间的点数为\(gcd(x1,y1) - gcd(x2,y2)\)个,但复杂度不能接受
因为每条直线的起点终点都在矩形上,我们可以(n + m) * (n + m)枚举四条边上的点,C(k,3)统计
*枚举一个点的坐标,它与(0,0)显然构成了唯一的一条线段,然后我们发现这条线段其实可以移动,所以就将一条线段的解\(\times (n-x) \times(m-y)\)

代码

#include<cstdio> 
#include<algorithm> 
 
#define int long long
 
inline int read() { 
    int x = 0 ,f = 1;
    char c = getchar() ; 
    while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar(); } 
    while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = getchar(); 
    return x * f; 
} 
const int maxn = 2007;  
int n,m; 
inline int C(int n) { return n * (n - 1) * (n - 2) / 6;  }
struct Node {
    int x,y;
    Node (int X = 0,int Y = 0) : x(X),y(Y) {}; 
 
} a[maxn],b[maxn];  
int gcd(int x,int y) {
    if(y == 0) return x; 
    else return gcd(y,x % y); 
}  
main() { 
    n = read(),m = read(); 
    n ++ ,m ++; 
    int ans = 0; 
    ans += C(n * m); 
    //printf("%d\n",ans);
    ans -= m * C(n); 
    ans -= n * C(m); int num  = 0,num2 = 0;
    for(int i = 1;i <= n;++ i)
            for(int j = 1;j <= m;++ j)
                    ans -= 2 * (gcd(i,j) - 1) * (n - i) * (m - j); 
        //printf("%d\n",ans);   
    printf("%lld\n",ans); 
    return 0;
} 
        
posted @ 2018-05-11 06:28  zzzzx  阅读(163)  评论(0编辑  收藏  举报