zoukankan      html  css  js  c++  java
  • 【洛谷P3166】数三角形

    题目

    题目链接:https://www.luogu.com.cn/problem/P3166
    给定一个 \(N\times M\) 的网格,请计算三点都在格点上的三角形共有多少个。注意三角形的三点不能共线。

    思路

    考虑总方案数减去三点共线的方案数。枚举每一个点 \((x,y)\),然后再枚举在 \((x,y)\) 左下角的一个点 \((k,l)\),那么在这两个点之间的点有 \(\gcd(i-k,j-l)-1\) 个。
    但是当这三个点所构成直线斜率为负数的时候,方案数我们不会计算到,由于每一个斜率为正数的直线旋转 \(90°\) 都可以得到一条斜率为负数的直线,所以 \(ans\) 直接乘上 \(2\),然后减去三点在同一行或同一列的方案数。
    后者可以直接 \(O(nm)\) 组合数暴力求出,对于 \(ans\) 直接预处理 \(\gcd\) 的前缀和乱搞即可。
    时间复杂度 \(O(nm)\)

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const ll N=1010;
    ll n,m,ans,sum[N][N];
    
    ll gcd(ll x,ll y)
    {
    	if (!y) return x;
    	return gcd(y,x%y);
    }
    
    int main()
    {
    	scanf("%lld%lld",&n,&m);
    	n++; m++;
    	for (ll i=0;i<=max(n,m);i++)
    		sum[i][0]=sum[0][i]=sum[0][i-1]+i;
    	for (ll i=1;i<=n;i++)
    		for (ll j=1;j<=m;j++)
    		{
    			sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+1LL*gcd(i,j);
    			ans+=sum[i-1][j-1]-i*j+1LL;
    		}
    	ans*=2LL;
    	for (ll i=1;i<=n;i++)
    		for (ll j=1;j<=m;j++)
    			ans-=((i-2LL)*(i-1LL)/2LL+(j-2LL)*(j-1LL)/2LL);
    	ll cnt=n*m;
    	printf("%lld",cnt*(cnt-1)*(cnt-2)/6-ans);
    	return 0;
    }
    
  • 相关阅读:
    Octave/Matlab初步学习
    week_3
    week_2
    week_1
    清除input[type=number]的默认样式
    js,获取和设置cookie、 localStorage
    php表单提交时获取不到post数据的解决方法
    console.log 简写
    JS合并两个数组的方法
    javascript ES5、ES6的一些知识
  • 原文地址:https://www.cnblogs.com/stoorz/p/13747132.html
Copyright © 2011-2022 走看看