【BZOJ3518】点组计数 [欧拉函数]

点组计数

Time Limit: 20 Sec  Memory Limit: 128 MB
[Submit][Status][Discuss]

Description

平面上摆放着一个n*m的点阵(下图所示是一个3*4的点阵)。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

Main idea

  给定一个点阵,问有多少组三点共线。

Source

  其实我也不知道原式怎么来的,我可能只会推式子啊?QAQ

Code

 1 #include<iostream>
 2 #include<string>
 3 #include<algorithm>
 4 #include<cstdio>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<cmath>
 8 using namespace std;
 9 typedef long long s64;
10
11 const int ONE = 50005;
12 const int MOD = 1000000007;
13 const int Ny6 = 166666668;
14
15 int T;
16 int n,m;
17 bool isp[ONE];
18 int prime[ONE],p_num;
19 int phi[ONE];
20 s64 Ans;
21
22 int get()
23 {
24         int res=1,Q=1;  char c;
25         while( (c=getchar())<48 || c>57)
26         if(c==‘-‘)Q=-1;
27         if(Q) res=c-48;
28         while((c=getchar())>=48 && c<=57)
29         res=res*10+c-48;
30         return res*Q;
31 }
32
33 void Getphi(int MaxN)
34 {
35         phi[1] = 1;
36         for(int i=2; i<=MaxN; i++)
37         {
38             if(!isp[i])
39                 prime[++p_num] = i, phi[i] = i - 1;
40             for(int j=1; j<=p_num, i*prime[j]<=MaxN; j++)
41             {
42                 isp[i * prime[j]] = 1;
43                 if(i % prime[j] == 0)
44                 {
45                     phi[i * prime[j]] = (s64)phi[i] * prime[j] % MOD;
46                     break;
47                 }
48                 phi[i * prime[j]] = (s64)phi[i] * phi[prime[j]] % MOD;
49             }
50         }
51 }
52
53 s64 Get(int a,int b,int num) {return (s64)(a+b) * num / 2 %MOD; }
54 s64 Sum(int n,int m) {return ((s64)n*(n-1)/2%MOD) * ((s64)m*(m-1)/2%MOD) % MOD;}
55
56 int C(int n)
57 {
58         int res = (s64)n * (n-1) % MOD * (n-2) % MOD;
59         return (s64) res * Ny6 % MOD;
60 }
61
62 int main()
63 {
64         Getphi(ONE-1);
65         n=get();    m=get();
66         if(n > m) swap(n,m);
67         for(int d=1; d<=n; d++)
68         {
69             Ans += phi[d] * Get(n-d,n-(n/d)*d,n/d) % MOD *Get(m-d,m-(m/d)*d,m/d) % MOD;
70             Ans %= MOD;
71         }
72
73         Ans = (Ans - Sum(n,m) + MOD) % MOD;
74         Ans = Ans*2%MOD + (s64)C(n)*m%MOD + (s64)C(m)*n%MOD;
75         Ans %= MOD;
76
77         printf("%lld",Ans);
78 }

时间: 2024-08-07 08:29:15

【BZOJ3518】点组计数 [欧拉函数]的相关文章

poj 2154 Color(polya计数 + 欧拉函数优化)

http://poj.org/problem?id=2154 大致题意:由n个珠子,n种颜色,组成一个项链.要求不同的项链数目,旋转后一样的属于同一种,结果模p. n个珠子应该有n种旋转置换,每种置换的循环个数为gcd(i,n).如果直接枚举i,显然不行.但是我们可以缩小枚举的数目.改为枚举每个循环节的长度L,那么相应的循环节数是n/L.所以我们只需求出每个L有多少个i满足gcd(i,n)= n/L,就得到了循环节数为n/L的个数.重点就是求出这样的i的个数. 令cnt = gcd(i,n) =

poj2409 &amp; 2154 polya计数+欧拉函数优化

这两个题都是项链珠子的染色问题 也是polya定理的最基本和最经典的应用之一 题目大意: 用m种颜色染n个珠子构成的项链,问最终形成的等价类有多少种 项链是一个环.通过旋转或者镜像对称都可以得到置换 旋转可以旋转 i=[1,n]次..画图可以看出循环节有gcd(n,i)个 镜像对称的置换画个图也是很容易找的 然后通过polya定理就可以容易的求出等价类的种数了 2409就是这样一个裸题,以下为ac代码 #include <iostream> #include <stdio.h> #

[ACM] POJ 2154 Color (Polya计数优化,欧拉函数)

Color Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 7630   Accepted: 2507 Description Beads of N colors are connected together into a circular necklace of N beads (N<=1000000000). Your job is to calculate how many different kinds of th

poj 2154 Color 欧拉函数优化的ploya计数

枚举位移肯定超时,对于一个位移i,我们需要的是它的循环个数,也就是gcd(i,n),gcd(i,n)个数肯定不会很多,因为等价于n的约数的个数. 所以我们枚举n的约数,对于一个约数k,也就是循环个数为n/k这样的个数有phi[k]种,证明网上有很多.所以答案就是 phi[k]*(pow(n,n/k)) (k是n的所有约数) 由于约数会很大所以不能打表,只能单个算. 再由于最后要除以n,如果做除法就不能直接取模,所以我们在算每一次pow(n,n/k)的时候,都少乘一个n,这样就相当于除法了. #i

hdu (欧拉函数+容斥原理) GCD

题目链接http://acm.hdu.edu.cn/showproblem.php?pid=1695 看了别人的方法才会做 参考博客http://blog.csdn.net/shiren_Bod/article/details/5787722 题意 a,b,c,d,k五个数,a与c可看做恒为1,求在a到b中选一个数x,c到d中选一个数y,使得gcd(x,y)等于k,求x和y有多少对. 首先可以想到选取的必是k的倍数,假设是x和y倍,则x和y一定是互质的在,那么就变成了求1到b/k和1到d/k的之

POJ 2478 欧拉函数(欧拉筛法) HDU 1576 逆元求法

相关逆元求法,我之前有写过,还有欧拉函数的求法,欧拉函数与逆元的关系  点击 POJ 2478 又是一个打表的题目,一眼看出结果就是前n个欧拉函数值的和. 这里直接计算欧拉函数值求和会超时,看见多组数据. 然后就是计算欧拉函数,打表就好了. #include <stdio.h> #include <string.h> #include <iostream> using namespace std; typedef long long LL; const int N =

HDU 5430 Reflect(欧拉函数)

题目: http://acm.hdu.edu.cn/showproblem.php?pid=5430 从镜面材质的圆上一点发出一道光线反射NNN次后首次回到起点. 问本质不同的发射的方案数. 输入描述 第一行一个整数T,表示数据组数.T≤10T \leq 10T≤10 对于每一个组,共一行,包含一个整数,表示正整数N(1≤N≤106)N(1 \leq N \leq 10^{6})N(1≤N≤10?6??). 输出描述 对于每一个组,输出共一行,包含一个整数,表示答案. 输入样例 1 4 输出样例

XMU 1615 刘备闯三国之三顾茅庐(三) 【欧拉函数+快速幂+欧拉定理】

1615: 刘备闯三国之三顾茅庐(三) Time Limit: 1000 MS  Memory Limit: 128 MBSubmit: 45  Solved: 8[Submit][Status][Web Board] Description 刘备(161年-223年6月10日),字玄德,东汉末年幽州涿郡涿县,西汉中山靖王刘胜的后代.刘备一生极具传奇色彩,早年颠沛流离.备尝艰辛最终却凭借自己的谋略终成一方霸主.那么在那个风云激荡的年代,刘备又是如何从一个卖草鞋的小人物一步一步成为蜀汉的开国皇帝呢

BZOJ2190 [SDOI2008]仪仗队(欧拉函数)

与HDU2841大同小异. 设左下角的点为(1,1),如果(1,1)->(x,y)和(1,1)->(x',y')向量平行,那只有在前面的能被看见.然后就是求x-1.y-1不互质的数对个数. 而x或y等于1可以另外讨论一下,就是当n不等于1时就有两个,n等于1就特判一下. 那么就用欧拉函数计数了:枚举x-1,累加小于x-1与x-1互质的个数,即合法的y-1的个数:结果还要*2,因为还有一半对称的y-1>x-1的情况:此外x-1=y-1多算了一次,减去1即可. 1 #include<c