BZOJ3560 DZY Loves Math V 数论 快速幂
原文链接http://www.cnblogs.com/zhouzhendong/p/8111725.html
UPD(2018-03-26):蒟蒻回来重新学数论了。更新了题解和代码。之前的怼到后面去了。
题目传送门 - BZOJ3560
题意概括
给定$n$个正整数$a_1,a_2,a_3,...,a_n$,求
$$\Huge\sum_{i_1|a_1}\sum_{i_2|a_2}\cdots \sum_{i_n|a_n}\varphi(i_1i_2i_3...i_n)$$
答案对$10^9+7$取模。
$1\leq n\leq 10^5,1\leq a_i\leq 10^7$
题解
考虑到$\varphi$是积性函数,所以我们可以对于每一个质数分别考虑。
对于每一个质数,考虑它有哪些情况,同一个质数的所有情况贡献加起来,然后不同质数的答案乘起来就OKla。
考虑对一个质数的处理。
先处理出每一个$a_i$含有该质因子几个(假设有$t_i$个)。保存好。
我们显然不可能穷举所有情况。我们考虑采用不同的$a_i$分开贡献的方式。
由于(p为质数)$f(p)=p-1,f(p^i)=f(p^{i-1})*p$,于是一开始的那个$f(p)=p-1$就特别令人不爽!!
于是我们暂且假装$f(p)=p$。这样的话,数$a_i$的贡献就是$\sum_{j=0}^{t_i}f(p^j)$。
于是算出来的当前质数的总贡献就是$\prod_{i=1}^{n}\sum_{j=0}^{t_i}f(p^j)$。
那个$\sum_{j=0}^{k}f(p^j)$可以预处理。
但是别忘了这个是个假贡献。我们假装了$f(p)=p$,事实上不是。
我们考虑还原。
该贡献可以分成两个部分:
1.$\prod_{j=1}^{n}i_j$中不含该质数因子,贡献为1。
2.包含,贡献比标准多了$\frac{1}{p-1}$。
于是搞个逆元还原一下2的部分就可以得到正确答案了。
具体实现大概我知道的有2种方式。
设$m=max\{a_i,i\in[1,n]\}$。
一种是我之前抄的做法:先分解n个数,然后按照质因子排序分段处理。时间复杂度$O(n \sqrt m +n log\ m)$。
一种是我这次写的做法:先筛法把小于$\sqrt m$的素数筛出来,然后对于每一个因子枚举n个数统计相关信息。对于大于$\sqrt m$的质因数用map存下来。最后一个一个算质数贡献。复杂度相同。常数貌似变小了。(BZOJ上快了近4倍)
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5+5,M=1e7+5,mod=1e9+7;
int prime[N],pcnt,ptot[N][30];
bool f[M];
map <int,int> hptot;
void get_prime(){
pcnt=0;
memset(f,true,sizeof f);
f[0]=f[1]=0;
for (int i=2;i*i<M;i++){
if (!f[i])
continue;
prime[++pcnt]=i;
for (int j=1;j<=i;j++)
f[i*j]=0;
}
}
LL Pow(LL x,LL y){
if (!y)
return 1LL;
LL xx=Pow(x,y/2);
xx=xx*xx%mod;
if (y&1LL)
xx=xx*x%mod;
return xx;
}
LL Inv(LL x){
return Pow(x,mod-2);
}
int n,a[N],v[N],cntv=0;
int main(){
get_prime();
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
memset(ptot,0,sizeof ptot);
hptot.clear();
for (int i=1;i<=pcnt;i++)
for (int j=1;j<=n;j++){
int k=0;
while (a[j]%prime[i]==0)
a[j]/=prime[i],k++;
ptot[i][k]++;
}
for (int i=1;i<=n;i++)
if (a[i]>1){
if (hptot[a[i]]==0)
v[++cntv]=a[i];
hptot[a[i]]++;
}
LL ans=1;
for (int i=1;i<=pcnt;i++){
LL phi=prime[i]+1,add=1;
for (int j=1;j<30;j++){
while (ptot[i][j]--)
add=add*phi%mod;
phi=(phi*prime[i]+1)%mod;
}
ans=ans*((add-1+mod)%mod*Inv(prime[i])%mod*(prime[i]-1)%mod+1)%mod;
}
for (int i=1;i<=cntv;i++){
LL phi=v[i]+1,add=1;
while (hptot[v[i]]--)
add=add*phi%mod;
ans=ans*((add-1+mod)%mod*Inv(v[i])%mod*(v[i]-1)%mod+1)%mod;
}
printf("%lld",ans);
return 0;
}
——————Old——————
题意概括
给定n个正整数a1,a2,…,an,求
的值(答案模10^9+7)。
1<=n<=10^5,1<=ai<=10^7。
题解
本人是蒟蒻。
可以看这位大佬的(给出链接)
http://blog.csdn.net/popoqqq/article/details/42739963
代码
呵呵,调试的时候照着他的改,改的几乎一样……
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long LL;
const LL N=100005;
LL mod=1e9+7;
LL n,tot=0;
struct Node{
LL p,t;
}q[N*20];
bool operator < (Node a,Node b){
return a.p<b.p;
}
void fj(LL v){
for (LL i=2;i*i<=v;i++)
if (v%i==0){
q[++tot].p=i;
q[tot].t=0;
while (v%i==0)
v/=i,q[tot].t++;
}
if (v>1)
q[++tot].p=v,q[tot].t=1;
}
LL Pow(LL x,LL y,LL mod){
if (y==0)
return 1LL;
LL xx=Pow(x,y/2,mod);
xx=xx*xx%mod;
if (y&1LL)
xx=xx*x%mod;
return xx;
}
LL Inv(LL x,LL mod){
return Pow(x,mod-2,mod);
}
LL calc(LL L,LL R){
LL sum[30];
LL p=q[L].p,res=1;
sum[0]=1;
for (int i=1;i<30;i++)
sum[i]=(sum[i-1]*p+1)%mod;
for (int i=L;i<=R;i++)
res=res*sum[q[i].t]%mod;
res=(res-1)*(p-1)%mod*Inv(p,mod)%mod+1;
return res%mod;
}
int main(){
scanf("%lld",&n);
for (int i=1,a;i<=n;i++){
scanf("%lld",&a);
fj(a);
}
sort(q+1,q+tot+1);
int last=0;
LL ans=1;
for (int i=1;i<=tot;i++)
if (i==tot||q[i].p!=q[i+1].p)
ans=ans*calc(last+1,i)%mod,last=i;
printf("%lld",(ans%mod+mod)%mod);
return 0;
}
BZOJ3560 DZY Loves Math V 数论 快速幂的更多相关文章
- BZOJ3561 DZY Loves Math VI 数论 快速幂 莫比乌斯反演
原文链接http://www.cnblogs.com/zhouzhendong/p/8116330.html UPD(2018-03-26):回来重新学数论啦.之前的博客版面放在更新之后的后面. 题目 ...
- BZOJ3560 DZY Loves Math V(欧拉函数)
对每个质因子分开计算再乘起来.使用类似生成函数的做法就很容易统计了. #include<iostream> #include<cstdio> #include<cmath ...
- BZOJ3560 : DZY Loves Math V
因为欧拉函数是非完全积性函数,所以可以考虑对每个数进行分解质因数,将每个质数的解乘起来即可. 对于一个质数$p$,设它在各个数中分别出现了$b_1,b_2,...b_n$次,那么由生成函数和欧拉函数的 ...
- [BZOJ3560]DZY Loves Math V(欧拉函数)
https://www.cnblogs.com/zwfymqz/p/9332753.html 由于欧拉函数是积性函数,可以用乘法分配律变成对每个质因子分开算最后乘起来.再由欧拉函数公式和分配律发现就是 ...
- 【BZOJ 3560】 3560: DZY Loves Math V (欧拉函数)
3560: DZY Loves Math V Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 241 Solved: 133 Description ...
- 【BZOJ3960】DZY Loves Math V(数论)
题目: BZOJ3560 分析: orz跳瓜. 欧拉函数的公式: \[\phi(n)=n(\prod \frac{p_i-1}{p_i})\] 其中 \(p_i\) 取遍 \(n\) 的所有质因子. ...
- 【bzoj3560】DZY Loves Math V 欧拉函数
题目描述 给定n个正整数a1,a2,…,an,求 的值(答案模10^9+7). 输入 第一行一个正整数n. 接下来n行,每行一个正整数,分别为a1,a2,…,an. 输出 仅一行答案. 样例输入 3 ...
- bzoj 3560 DZY Loves Math V - 线性筛 - 扩展欧几里得算法
给定n个正整数a1,a2,…,an,求 的值(答案模10^9+7). Input 第一行一个正整数n. 接下来n行,每行一个正整数,分别为a1,a2,…,an. Output 仅一行答案. Sampl ...
- bzoj DZY Loves Math V
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 509 Solved: 284[Submit][Status][Discuss] Descriptio ...
随机推荐
- linux /proc目录
1. /proc目录Linux 内核提供了一种通过 /proc 文件系统,在运行时访问内核内部数据结构.改变内核设置的机制.proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间.它以文 ...
- HDU 4455
题意 : 题目 给你一个序列 , 查询 t ,问 序列 连续 长度为 t 的子区间 的不同数 的和 巧妙的动态规划 数据大, Dp可以 O(n) #include<iostream> # ...
- Linux之 nginx-redis-virtualenv-mysql
mysql maraidb相关 .yum安装好,启动 安装: yum install mariadb-server mariadb 启动mabiadb: systemctl start mariadb ...
- IPFS环境安装
IPFS是一个分布式的P2P的协议,可能会取代这个http,全球的点都可能存储这个数据 IPFS搭建环境 1.首先是下载节点软件到官网下载windows版本的ipfs节点软件,如果不能访问官网的话,可 ...
- 每天备份tomcat日志
#!/bin/bash Backup_Home=/data/backup-log mkdir -p $Backup_Home Log_Home=/data/Tomcat/logs App_Log_Ho ...
- SQL*Plus工具
或者
- Confluence 6 使用 Apache 的 mod_jk
在 Confluence 6 及其后续版本中,不能使用 mod_jk 来做代理.这是因为 Synchrony 服务导致的这个限制. Synchrony 在协同编辑的时候需要启动,同时还不能接受 A ...
- NIO(三)
使用直接缓冲区完成文件的复制(内存映射文件) package com.cppdy.nio; import java.nio.MappedByteBuffer; import java.nio.chan ...
- day07 元组类型 字典类型 集合
元组:元组就是一个不可变的列表 1.用途:当我们需要记录多个同种属性的值,并且只有读的需求,没有改的需求,应该用元组. 2.定义方式:在()内用逗号分隔开多个任意类型的元素 t=(‘egon’)#注意 ...
- Intenet 地址
java.net.InetAddress类是java对Ip地址(包括ipv4和ipv6)的高层表示,大多数其他网络类都要用到这个类,包括Socket, ServerSocket, URL, Datag ...