• P3166 [CQOI2014]数三角形


    题目

    P3166 [CQOI2014]数三角形

    分析

    数三点不共线显然不如数三点共线(其实是因为在这个之前做了一道不共线的 BZOJ3518点组计数。)

    首先除去边角的三点共线,因为很好算,我们就可以只考虑斜着的三点共线。

    直接枚举两个点代价太大,而枚举一个点信息又太少,于是考虑枚举第一个点和第三个点的横纵坐标之差,考虑有这样的差的对数有多少个呢? ((n-i)(m-j)) 个 。

    这样第二个点的个数就可以确定了是 (gcd(i,j)-1) ,直接乘起来然后求和即可。

    现在问题转化成求 large sumlimits_{i=1}nsumlimits_{j=1}m(gcd(i,j)-1)(n-i)(m-j) 的值。

    large sumlimits_{i=1}nsumlimits_{j=1}m(gcd(i,j)-1)(n-i)(m-j)

    large =sumlimits_{i=1}nsumlimits_{j=1}m(gcd(i,j))(n-i)(m-j)-sumlimits_{i=1}n{sumlimits_{j=1}m{ij}}

    large =sumlimits_{d=1}{min(n,m)}{varphi{(d)}sumlimits_{i=1}{lfloor dfrac{n}{d} floor}{(n-di)sumlimits_{j=1}^{lfloor dfrac{m}{d} floor}(m-dj)}}-sumlimits_{i=1}{n-1}{isumlimits_{j=1}{m-1}{j}}

    因为 n,m 很小,所以可以直接暴力计算。(注意中间两个求和柿子就是等差数列,我当时竟然没看出来。。)

    最后使用减法原理即可。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    template <typename T>
    inline void read(T &x){
        x=0;char ch=getchar();bool f=false;
        while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
        while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        x=f?-x:x;
        return ;
    }
    template <typename T>
    inline void write(T x){
        if(x<0) putchar('-'),x=-x;
        if(x>9) write(x/10);
        putchar(x%10^48);
        return ;
    }
    #define ll long long
    #define ull unsigned long long
    const int N=1e6+5,M=1e6+5,MOD=1e9+7;
    ll n,m;
    ll cnt,prime[N],f[N],low[N];
    bool vis[N];
    inline void GetPrimes(int d){
    	vis[1]=true;f[1]=low[1]=1;//对1进行定义 
    	for(ll i=2;i<=d;i++){
    		if(!vis[i]) prime[++cnt]=low[i]=i,f[i]=i-1;//对质数进行定义 
    		for(ll j=1;j<=cnt&&i*prime[j]<=d;j++){
    			vis[i*prime[j]]=true;
    			if(i%prime[j]==0){
                    low[i*prime[j]]=low[i]*prime[j];
                    if (low[i]==i) f[i*prime[j]]=f[i]*prime[j];//对质数的若干次幂进行定义(一般由f[i]递推);
                    else f[i*prime[j]]=f[i/low[i]]*f[low[i]*prime[j]];
                    break;
                }
                low[i*prime[j]]=prime[j];
    			f[i*prime[j]]=f[i]*f[prime[j]];
    		}
    	}
    	return ;
    }
    int main(){
    	GetPrimes(1001);
    	read(n),read(m);n++,m++;
    	ll d=min(n,m);ll Ans=0;
    	for(ll i=1;i<=d;i++) Ans=(Ans+f[i]*((n-i+n%i)*((int)floor(n/i))/2)*((m-i+m%i)*((int)floor(m/i))/2));
    	Ans-=n*(n-1)/2*m*(m-1)/2;
    	Ans=(Ans+Ans);
    	Ans=(Ans+n*(m*(m-1)*(m-2)/6)+m*(n*(n-1)*(n-2)/6));
    	Ans=n*m*(n*m-1)*(n*m-2)/6-Ans;
    	write(Ans);
    	return 0;
    }
    
  • 相关阅读:
    Office转SWF的一些感想(Office2007和Office2010)
    数据库字段为日期类型时
    C#实现office文档转换为PDF格式
    C#.net word excel powerpoint (ppt) 转换成 pdf 文件
    Servlet基础
    Android加速度传感器实现“摇一摇”,带手机振动
    android完全退出应用程序
    【安卓笔记】作为内部类的广播接收者
    Android中使用广播机制退出多个Activity
    [Android] ImageView.ScaleType设置图解
  • 原文地址:https://www.cnblogs.com/Akmaey/p/15174615.html
Copyright © 2020-2023  润新知