zoukankan      html  css  js  c++  java
  • [BZOJ3518] 点组计数

    [BZOJ3518] 点组计数

    Description

    平面上摆放着一个nm的点阵(下图所示是一个34的点阵)。Curimit想知道有多少三点组(a,b,c)满足以a,b,c三点共线。这里a,b,c是不同的3个点,其顺序无关紧要。(即(a,b,c)和(b,c,a)被认为是相同的)。由于答案很大,故你只需要输出答案对1,000,000,007的余数就可以了。

    Input

    有且仅有一行,两个用空格隔开的整数n和m。

    Output

    有且仅有一行,一个整数,表示三点组的数目对1,000,000,007的余数。(1,000。000。007是质数)

    Sample Input

    3 4

    Sample Output

    2 0

    HINT

    对于100%的数据,1< =N.m< =50000

    试题分析

    由于两点确定一条直线,所以常规思想就是枚举一条线段,然后计算中间有多少点。
    因为在坐标系中竖线和横线特殊,所以我们单拿出来考虑,就是:$$inom {n}{3} imes m + inom {m}{3} imes n$$
    那么怎么求一条线段中间有多少点呢?假设枚举到的两个点为(p_1)(p_3),它们的横、纵坐标差为(i)(j)
    然后还要设中间的点坐标为(p_2),它们的横、纵坐标差为(x)(y)
    显然斜率唯一,所以斜率要相等,也就是:$$frac{j}{i}=frac{y}{x}$$

    [frac{x}{i}=frac{y}{j} ]

    [x=y imes frac{i}{j} ]

    [x=y imes frac{frac{i}{gcd(i,j)}}{frac{j}{gcd(i,j)}} ]

    于是(frac{j}{gcd(i,j)} | y)(yleq j),所以(cnt_y=frac{j}{frac{j}{gcd(i,j)}})
    由于每一个(y)对应一个(x),所以不需要讨论(x)了。
    那么能取的合法的点就是(gcd(i,j)-1)个(还要减去(y=i)的情况)
    那么就是求:$$ans=2 imes sum_{i=1}{n-1}sum_{j=1}{m-1} (n-i)(m-j)(gcd(i,j)-1)$$
    根据欧拉反演有:$$ans=2 imes sum_{i=1}{n-1}sum_{j=1}{m-1} (n-i)(m-j)(sum_{d|i,d|j} phi(d) -1)$$
    然后变成枚举(d):$$ans=2 imes(sum_limits{d=1}^{min(n-1,m-1)} phi(d) sum_limits{i=1}^{lfloor frac{n-1}{d} floor} sum_limits{j=1}^{lfloor frac{m-1}{d} floor} (n-id)(n-jd) - sumlimits_{i=1}nsumlimits_{j=1}m (n-i)(m-j))$$
    枚举计算即可。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<algorithm>
      
    using namespace std;
    #define LL long long
      
    inline LL read(){
        LL x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    const LL MAXN = 200010;
    const LL INF = 2147483600;
    const LL Mod = 1000000007;
    const LL inv2 = 500000004;
    const LL inv6 = 166666668;
      
    LL N,M; LL pri[MAXN+1],phi[MAXN+1],cnt; bool vis[MAXN+1];
    inline void init(){
        vis[1]=1; phi[1]=1;
        for(LL i=2;i<MAXN;i++){
            if(!vis[i]) pri[++cnt]=i,phi[i]=i-1;
            for(LL j=1;j<=cnt&&pri[j]*i<MAXN;j++){
                vis[i*pri[j]]=true;
                if(i%pri[j]==0) {phi[pri[j]*i]=pri[j]*phi[i]; break;}
                phi[pri[j]*i]=(pri[j]-1)*phi[i];
            }
        } return ;
    }
    inline LL cal(LL n,LL k,LL d){
        return 1LL*(k*n%Mod-1LL*d*(k+1)%Mod*k%Mod*inv2%Mod+Mod)%Mod;
    }
    inline LL C(LL b){
        return b*(b-1)%Mod*(b-2)%Mod*inv6%Mod;
    }
      
    int main(){
        //freopen(".in","r",stdin);
        //freopen(".out","w",stdout);
        N=read(),M=read(); init(); LL ans=0;
        if(N>M) swap(N,M);
        for(LL i=1;i<=N;i++){
            ans=ans+phi[i]*cal(M,M/i,i)%Mod*cal(N,N/i,i)%Mod;
            ans%=Mod;
        } ans=(ans-((N-1)*N%Mod*inv2%Mod*(M-1)*M%Mod*inv2%Mod)+Mod)%Mod;
        printf("%lld
    ",(2*ans+C(M)%Mod*N%Mod+C(N)%Mod*M%Mod)%Mod);
        return 0;
    }
    
    
  • 相关阅读:
    中缀表达式求值
    520的信心赛——点点玩deeeep
    520的信心赛——麓麓学数学
    l洛谷 (水题)P4144 大河的序列
    洛谷 P3391 【模板】文艺平衡树(Splay)
    在洛谷3369 Treap模板题 中发现的Splay详解
    洛谷 P1344 [USACO4.4]追查坏牛奶Pollutant Control
    洛谷 P1678 烦恼的高考志愿
    洛谷 P2421 A-B数对(增强版)
    P3381 【模板】最小费用最大流
  • 原文地址:https://www.cnblogs.com/wxjor/p/9552995.html
Copyright © 2011-2022 走看看