2014.11.12模拟赛【最大公因数】

最大公因数(gcd.c/.cpp/.pas)

题目描述

给定正整数n,求。

样例输入

6

样例输出

15

数据范围

对于40%的数据:1<=n<=1000000

对于100%的数据:1<=n<=3*10^12

提示:保证答案不超过10^18

原创题!

……好吧其实最后发现bzoj2705【longge的问题】跟这个一毛一样,但是这个数据更强

不过我真是独立yy出来的

首先,考虑gcd(i,n)==k的i有几个

显然这是等价于gcd(j,n/k)==1的j有几个,其中1<=j<=n/k

看到gcd==1,即j与n/k互质,你想到什么?显然是欧拉函数啊

gcd(j,n/k)==1的j的个数就是phi(n/k),其中每个gcd(i,n)==k对答案的贡献是k,所以总的答案就是Σphi(n/k)*k,1<=k<=n且n%k==0

显然这个式子等价于Σphi(k)*(n/k),1<=k<=n且n%k==0

那么对n分解质因数,然后枚举它的每个因子取了多少个,算phi(k)*(n/k)就近似O(1)了

总复杂度是O(sqrt(n))

(所以完全可以开到10^15的,只是怕爆了long long要高精太麻烦)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<deque>
#include<set>
#include<map>
#include<ctime>
#define LL long long
#define inf 0x7ffffff
#define pa pair<int,int>
#define mxprime 1500000
using namespace std;
bool mrk[1500010];
LL prime[1000000],a[100];
LL n,wrk,ans;
int lenp,len;
int b[100],now[100];
inline LL read()
{
    LL x=0,f=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
inline void getprime()
{
	for (int i=2;i<=mxprime;i++)
	  mrk[i]=1;
	for (int i=2;i<=mxprime;i++)
	  if (mrk[i])
	  {
	  	prime[++lenp]=(LL)i;
	  	for(int j=2*i;j<=mxprime;j+=i)mrk[j]=0;
	  }
}
inline void dfs(int step)
{
	if (step==len+1)
	{
		LL sum=1ll,tot=1ll;
		for (int i=1;i<=len;i++)
		{
		  for (int j=1;j<=now[i];j++)
		    sum*=a[i],tot*=a[i];
		  if (now[i])sum=sum/a[i]*(a[i]-1);
		}
		ans+=sum*(n/tot);
		return;
	}
	for(int j=0;j<=b[step];j++)
	{
		now[step]=j;
		dfs(step+1);
	}
}
int main()
{
	getprime();
	n=wrk=read();
	for (int i=1;prime[i]*prime[i]<=wrk;i++)
	{
		LL nowp=prime[i];
		if (wrk%nowp==0)
		{
			a[++len]=nowp;
			b[len]=1;
			wrk/=nowp;
			while (wrk%nowp==0)
			{
				b[len]++;
				wrk/=nowp;
			}
		}
	}
	if (wrk!=1)
	{
		if (wrk==a[len])b[len]++;
		else
		{
			a[++len]=wrk;
			b[len]=1;
		}
	}
	dfs(1);
	printf("%lld\n",ans);
}

  

时间: 2024-11-05 22:25:11

2014.11.12模拟赛【最大公因数】的相关文章

2014.11.12模拟赛【最小公倍数】| vijos1047最小公倍数

最小公倍数(lcm.c/.cpp/.pas) 题目描述 给定两个正整数,求他们的最小公倍数. 样例输入 28 12 样例输出 84 数据范围 对于40%数据:1<=a,b<=10^9 对于60%的数据:1<=a,b<=10^12 对于100%数据:1<=a,b<=10^100 提示:为了略微降低题目难度,增加以下条件: 1. 输入数据保证a>=b 2. 输入数据保证a.b没有前导0 3. 输入数据保证除了在两个正整数a.b之间的空格和行末换行符以外,不存在其他非数

2014.11.12模拟赛【美妙的数字】| vijos1904学姐的幸运数字

美妙的数字(number.c/.cpp/.pas) 题目描述 黄巨大认为非负整数是美妙的,并且它的数值越小就越美妙.当然0是最美妙的啦. 现在他得到一串非负整数,对于每个数都可以选择先对它做二进制非运算(模二意义下0.1互换,注意前导0也要交换),然后在任意相邻的两个数之间插入二进制与.二进制或,或者二进制异或.现在他想知道这样计算完产生的最美妙的数字是多少. 一共T组数据.对于每组数据,第一行一个n,表示这组数据中一串数有多少个.下面n个非负整数,表示这串数. 样例输入 2 2 3 6 3 1

11.12 模拟赛T2 冒泡排序图

[问题描述] 有一段使用冒泡排序产生一张图的伪代码如下:function bubbleSortGraph(n, a[]): graph = emptyGraph() repeat swapped = false for i = 1 to n - 1:  if a[i] > a[i + 1]: graph.addEdge(a[i], a[i + 1]) swap(a[i], a[i + 1]) swapped = true until not swapped return graph函数的输入为长

11.12 模拟赛T1 加密

[问题描述] 有一种不讲道理的加密方法是: 在字符串的任意位置随机插入字符. 相应的, 不讲道理的解密方法就是从字符串中恰好删去随机插入的那些字符. 给定原文?和加密后的字符串?,求?有多少子串可以通过解密得到原文?. [输入格式] 输入第一行包含一个字符串?,第二行包含一个字符串?. [输出格式] 输出一行,包含一个整数,代表可以通过解密得到原文的?的子串的数量. [样例输入] abcabcabccba [样例输出] 9 [样例解释] 用[l,r]表示子串开头结尾的下标(从 0 开始编号) ,

2017.6.11 校内模拟赛

题面及数据及std(有本人的也有原来的) :2017.6.11 校内模拟赛 T1 自己在纸上模拟一下后就会发现 可以用栈来搞一搞事情 受了上次zsq 讲的双栈排序的启发.. 具体就是将原盘子大小copy一下排个序 用两个指针维护两个数组(原数据 和 排序后的数据), 即分为1数据和2数组 将小于1指针指向的数据的2数组中的数据全部压入栈中 后进行消除, 将栈栈顶元素与当前1数组中的1指针指向的元素进行比较 相同则消除 后重复过程 直至指针超过N 后判断一下是否两个指针都超过了N... #incl

11.27 模拟赛

并没有人做的模拟赛... 出题人hx,,, T1:就是上一道矩阵乘法 数学题 T2: 一个数列中 一个区间满足,存在一个k(L <= k <= R),并且对于任意的i (L <= i <= R),ai都能被ak整除 这样的一个特殊区间 [L, R]价值为R - L 想知道序列中所有特殊区间的最大价值是多少,而有多少个这样的区间呢 这些区间又分别是哪些呢 输出每个区间的L 思路: 用两个ST表分别求一段区间的gcd和最小值 然后可以二分答案 check的时候枚举左端点,判断在这段区间

2017 9 11 noip模拟赛T2

#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=205; int map[N][N]; int d[N],tag[N],book[N],f[N]; int n,m; void work(int x) { memset(d,63,sizeof(d)); memset(book,0,sizeof(book)); memset(f,0,sizeof(

11.4 模拟赛

终于AK了,虽然第三题主要是搞月想出来的 T1: n个1*1的小方块,把这些小方块拼成一个图形,使这个图形周长最小 思路: 枚举拼成长方形的长为i,宽为n/i 可得面积 (i+n/i+(bool)(n%i))*2 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<cmath> 6 #include<cstr

11.12模拟考T1(可持续优化)PS:神奇的东西

1.数列操作   (array.pas/c/cpp) [问题描述] 现在有一个数列,最初包含0个数.现在要对数列操作n次,操作有3类. 1) a k,在数列的最后插入一个整数k 2) s 将最近插入的数删除. 3) t k 将数列恢复第k次操作前的状态 下面是一个例子,有12个操作 1 a 5 -> [5] => 5 加入数5 2 a 3 -> [5,3] => 3 加入数3 3 a 7 -> [5,3,7] => 7 加入数7 4 s -> [5,3] =>