• bzoj3505: [Cqoi2014]数三角形 [数论][gcd]


    Description

    给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个。下图为4x4的网格上的一个三角形。

    注意三角形的三点不能共线。

    Input

    输入一行,包含两个空格分隔的正整数m和n。

    Output

    输出一个正整数,为所求三角形数量。

    Sample Input

    2 2

    Sample Output

    76

    数据范围
    1<=m,n<=1000

    太伤心了。。不能abs(int)???

    首先格点个数是(n+1)*(m+1)的,所以我们先把n和m都+1。 先选出三个不同点,方案数是C(n*m,3)。 接下来扣掉三点共线的情况。 枚举两个点,计算以它们为端点的线段上的整点个数。 不难发现是gcd(x1-x2,y1-y2)-1。 线段是可以平移的,那么我们把其中一个点固定在(0,0),只枚举另一个点的坐标,然后乘上方案数就行了。 时间复杂度O(nm)

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 using namespace std;
     5 #define dbg(x) cout<<#x<<" = "<<x<<endl
     6 
     7 typedef long long ll;
     8 
     9 const int maxn=1005;
    10 
    11 int n,m,f[maxn][maxn],ens;
    12 ll ans;
    13 
    14 ll C(int a,int b){
    15     ll res=1;
    16     for(int i=a;i>a-b;i--)  res*=i;
    17     for(int i=b;i>1;i--)  res/=i;
    18     return res;
    19 }
    20 
    21 int gcd(int a,int b){
    22     if(f[a][b])  return f[a][b];
    23     return b?(f[a][b]=gcd(b,a%b)):a;
    24 }
    25 
    26 int main(){
    27     scanf("%d%d",&n,&m);
    28     n++;  m++;
    29     ans=C(n*m,3);
    30     for(int i=-n+1;i<=n-1;i++)
    31         for(int j=0;j<=m-1;j++){
    32             //避免重复计算 
    33             if(!j&&i<=0)  continue;
    34             ens=gcd(i<0?-i:i,j)-1;
    35 //            dbg(abs(i));  dbg(j);  dbg(ens);
    36             ans-=1ll*ens*(n-(i<0?-i:i))*(m-j);
    37         }
    38     printf("%lld
    ",ans);
    39     return 0;
    40 }
  • 相关阅读:
    动态规划-树形dp
    排队打水
    耍杂技的牛
    合并果子
    贪心问题-区间类
    动态规划-状态压缩dp
    Linux分区知识及企业场景分区76
    企业面试题-find结合sed查找替换
    企业面试题-利用三剑客
    alias-unalias
  • 原文地址:https://www.cnblogs.com/ZYBGMZL/p/7284430.html
Copyright © 2020-2023  润新知