zoukankan      html  css  js  c++  java
  • P3166 数三角形

    题面

    计数题,听妙的。

    首先n ++,m ++;因为是格点数,题目给的是边长。

    考虑容斥,所有可能组成三角形的个数就是任意取三个点即C(nm,3)减去不合法的就是在同一条直线上的。

    同一条直线分为横竖斜。横竖直接考虑C(n,3)*m和C(m,3)*n

    斜边稍微复杂一点,画个图。

    我们考虑所有不合法的直线,两点确定一条直线,所以枚举两个点,复杂度O(n^2m^2)死掉了,把其中一个点等价转换到坐标系(0,0)点处,枚举另一个点。

    显然在这两条直线间经过的格点数目为gcd(i,j)-1。考虑如果gcd(i,j)==1,那么两点中间就是直接到达的。用反证法,如果gcd(i,j)!=1且中间没有点,那么(i/gcvd(i,j),j/gcd(i,j))这个点必定会挡住线段的两个端点,所以不成立。即两点之间格点数目为(gcd(i,j)-1)。当前i,j考虑的点由于两个端点固定,可以把他进行等价平移,平移个数就是(n-i)*(m-j),最后因为矩阵对称性,现在的直线相当于斜率为负,考虑斜率是正的时候*2,就好了。

     代码简单

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define int long long
    const int N = 1e3 + 10;
    
    int n, m;
    int a[N][N], cnt;
    int q[N<<2][2];
    int gcd(int a,int b){
        if(b == 0) return a;
        return gcd(b, a % b);
    }
    
    int sss;
    signed main(){
        cin >> n >> m;
        n ++;m ++;
        int ans = n * m;
        ans = ans * (ans - 1) * (ans - 2) / 6;
        ans = ans - (m * n * (n - 1) * (n - 2) / 6);
        ans = ans - (n * m * (m - 1) * (m - 2) / 6);
        for(int i = 1;i < n;++ i){
            for(int j = 1;j < m;++ j){
                ans -= 2 * (gcd(i,j)-1) * (n - i) * (m - j);
            }
        }
        cout << ans;
        return 0;
    }
  • 相关阅读:
    Javascript倒计时页面跳转
    php计算时间差的方法
    php mysqli多个查询的例子
    结束线程方法2 Java提供的中断机制
    结束线程方法1:使用退出标志
    Java并发编程面试题1
    生产者消费者 java.util.concurrent.lock包
    多线程实例1 一个线程写入人员信息,一个线程读取人员信息
    Java并发编程笔记
    mysql案例-sysbench安装测试
  • 原文地址:https://www.cnblogs.com/Shu-Kuang/p/13378512.html
Copyright © 2011-2022 走看看