【51nod1965】奇怪的式子
Solution
怎么说呢。。这题。。做的有点痛苦。。
首先看这个式子长得。。比较奇怪,指数里面那个加号有点烦人,而且这个函数不是一个积性函数也有点烦人,那就考虑把这个函数拆成两部分来算
\]
首先看第一部分的处理,我们记\(Sum(i)=\frac{n(n+1)}{2}\),那么有:
&\prod\limits_{i=1}^{n}\sigma_0(i)^i=\prod\limits_{p}\prod\limits_{k}(k+1)^W\\
&W=p^k\cdot Sum(\lfloor \frac{n}{p^k}\rfloor)-p^{k+1}\cdot Sum(\lfloor \frac{n}{p^k+1}\rfloor)\\
\end{aligned}
\]
具体一点的话就是,因为这里是连乘,然后\(\sigma_0(x)\)是一个积性函数,所以我们考虑将每一个\(i\)分解质因数,然后按照分解的质因数把每个\(\sigma_0\)写开
那么,枚举素数\(p\),枚举这个素数的指数\(k\),然后统计分解质因数后\(p\)的指数恰好为\(k\)的数的个数,然后算贡献就好了
然而这个式子还是不能直接用来求解第一部分的答案,所以我们还要进一步处理
考虑分成\(p<=\sqrt n\)和\(p>\sqrt n\)两类来看:
首先对于\(p<=\sqrt n\)的部分,是可以直接计算而不会T掉的
然后对于\(p>\sqrt n\)的部分,\(p\)的指数\(k\)只能是\(1\)(因为\(p>\sqrt n\)),所以:
&\prod\limits_{p>\sqrt n}\prod\limits_{k}(k+1)^W=\prod\limits_{p>\sqrt n}2^{W'}\\
&W'=Sum(\lfloor \frac{n}{p} \rfloor)\\
\end{aligned}
\]
这个部分的话,因为\(\lfloor \frac{n}{p}\rfloor\)的取值只有\(2\sqrt n\)个,所以我们可以直接用莫比乌斯反演中的那个常用技巧,分块一下求就可以了
然后整个过程中我们需要预先处理出来的东西有两个:约数个数和约数和
这两个东西用min_25筛一下就好了
然而!
这样我们求出来的是\(2\)的指数部分,这个数在计算的过程中如果不加取模操作的话会奇大无比,这就很尴尬
注意到题目中的模数是一个素数,那么我们可以用一下由欧拉定理得到的一个结论:
\]
也就是说我们可以对指数部分的计算\(\%\phi(p)\)(也就是\(p-1\)),并不会影响结果,问题解决ovo
然后看第二部分,这一个部分看上去会比较麻烦(实际上也确实有点麻烦)
把式子单独列出来:
\]
首先来分析一下什么样的\(i\)才会被算进去
由于\(\mu(i)\)有一个很好的性质:当\(i\)有平方因子的时候\(\mu(i)=0\),所以我们接下来对\(i\)的讨论可以多一个前提就是\(i\)分解质因数之后每一个素数的指数都是\(1\)
那么沿用处理第一部分的时候的想法,我们将每个\(i\)分解质因数拆开来写
用\(d(i)\)表示\(i\)的质因数个数,那么可以得到:
\]
有了上面的欧拉定理得到的结论支撑,我们就可以放心大胆地先求指数再求结果啦
用类似min_25筛中设状态的方式:
记\(minp(i)\)表示\(i\)的最小质因子,\(d(i)\)表示\(i\)的质因数个数,\(P\)为素数列表
首先大力定义
\]
然后为了方便转移我们还需要定义一个辅助数组
\]
那么我们可以得到转移:
&f1(i,j)=f1(i,j+1)+(-1)*(f1(\lfloor \frac{n}{P_j}\rfloor,j+1)-f1(P_j,j+1))\\
&f(i,j)=f(i,j+1)+(-1)*(f(\lfloor \frac{n}{P_j}\rfloor,j+1)-f(P_j,j+1))+(-1)*(f1(\lfloor \frac{n}{P_j}\rfloor,j+1)-f1(P_j,j+1))
\end{aligned}
\]
初始化\(f1(i,max)=f(i,max)=(-1)*[1,i]\)范围内素数个数,\(max\)表示的是\(>=\sqrt n\)的第一个素数在列表中的下标
具体一点的话就是,首先所有的\((-1)\)其实都是\(\mu (p)\)的值,因为是素数的\(\mu\)值所以是\(-1\)
然后转移的话其实就是要加上\([1,i]\)范围内的\(minp(x)=P_j\)的数的贡献,为了保证有\(P_j\)的存在并且是最小的,所以调用的是\(f(\lfloor\frac{n}{P_j}\rfloor,j+1)\)和\(f1(\lfloor\frac{n}{P_j}\rfloor,j+1)\),然后还要保证素数不会被多算一次所以要去掉素数部分也就是\(f(P_j,j+1)\)和\(f1(P_j,j+1)\)
然后就可以快乐dp得出答案啦
一些实现的细节问题:
1.这题的模数比较巨大,两个数的乘积可能爆long long,所以要。。用一个奇妙黑科技,也就是用long double 模拟取模这样来取模qwq
2.注意在算的过程中的模数到底是用\(\phi(MOD)\)还是\(MOD\)要看清楚。。调了好久。。
3.在求的过程中因为数字都比较巨大所以。。要积极取模
(调试调到后来直接放弃思考见到乘号就取模导致代码长得十分不可描述并且常数巨大qwq)
代码大概长这个样子
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define ld long double
using namespace std;
const int MAXN=1e6+10;
const ll MOD=1e12+39,PHIMOD=MOD-1;
ll pcnt[MAXN*2],psum[MAXN*2],g[MAXN*2],f[MAXN*2],f1[MAXN*2];
ll P[MAXN],rec[MAXN*2];
int loc1[MAXN],loc2[MAXN];
bool vis[MAXN];
ll n,m,sq,cnt,cntval,ans,T;
void prework(int n);
void init_loc();
void get_g();
int Pos(ll x){return x<=sq?loc1[x]:loc2[n/x];}
ll Sum(ll l,ll r);
ll ksm(ll x,ll y);
ll mul(ll x,ll y,ll mod){
ld tmp=(ld)x*(ld)y;
return (x*y-((ll)(tmp/(ld)mod)*mod)+mod)%mod;
}
void solve1();
void solve2();
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
scanf("%d",&T);
prework(MAXN);
for (int o=1;o<=T;++o){
scanf("%lld",&n);
sq=sqrt(n)+0.5;
m=upper_bound(P+1,P+1+cnt,sq)-P-1;
init_loc();
get_g();
ans=1;
solve1();
solve2();
printf("%lld\n",ans);
}
}
void prework(int n){
cnt=0;
for (int i=2;i<=n;++i){
if (!vis[i])
P[++cnt]=i;
for (int j=1;j<=cnt&&P[j]*i<=n;++j){
vis[i*P[j]]=true;
if (i%P[j]==0) break;
}
}
}
void init_loc(){
cntval=0;
for (ll i=1,pos;i<=n;i=pos+1){
rec[++cntval]=n/i;
pos=n/(n/i);
}
reverse(rec+1,rec+1+cntval);
for (int i=1;i<=cntval;++i)
if (rec[i]<=sq) loc1[rec[i]]=i;
else loc2[n/rec[i]]=i;
}
void get_g(){
for (int i=1;i<=cntval;++i)
pcnt[i]=rec[i]-1,psum[i]=Sum(1,rec[i])-1;
for (int j=1;j<=m;++j)
for (int i=cntval;i>=1&&rec[i]>=1LL*P[j]*P[j];--i){
pcnt[i]-=pcnt[Pos(rec[i]/P[j])]-pcnt[Pos(P[j]-1)];
psum[i]=(psum[i]+PHIMOD-P[j]*(psum[Pos(rec[i]/P[j])]+PHIMOD-psum[Pos(P[j]-1)])%PHIMOD)%PHIMOD;
}
}
ll Sum(ll l,ll r){
ll tmp=l+r,tmp1=r-l+1;
if (tmp&1) tmp1/=2;
else tmp/=2;
return mul(tmp,tmp1,PHIMOD);
}
ll ksm(ll x,ll y){
ll ret=1,base=x;
for (;y;y>>=1,base=mul(base,base,MOD))
if (y&1) ret=mul(ret,base,MOD);
return ret;
}
void solve1(){//\prod \sigma i^i
ll tmp;
for (int i=1;i<=m;++i){
tmp=P[i];
for (int k=1;tmp<=n;tmp*=P[i],++k)
ans=mul(ans,ksm(k+1,(tmp*Sum(1,n/tmp)%PHIMOD-tmp*P[i]%PHIMOD*Sum(1,n/(tmp*P[i]))%PHIMOD)+PHIMOD)%PHIMOD,MOD);
}
tmp=0;
for (int i=Pos(sq)+1;i<=cntval;++i)
tmp+=mul(Sum(1,n/rec[i]),(psum[i]-psum[i-1]+PHIMOD)%PHIMOD,PHIMOD);
ans=mul(ans,ksm(2,tmp),MOD);
}
void solve2(){//\prod \sigma i^{\mu i}
for (int i=2;i<=cntval;++i) f1[i]=f[i]=PHIMOD-pcnt[i];
for (int j=m;j>=1;--j){
for (int i=cntval;i>=2&&rec[i]>=P[j]*P[j];--i){
f1[i]=(f1[i]+(-1LL)*(f1[Pos(rec[i]/P[j])]-f1[Pos(P[j])]))%PHIMOD;
f[i]=(f[i]+(-1LL)*(f[Pos(rec[i]/P[j])]-f[Pos(P[j])])+(-1LL)*(f1[Pos(rec[i]/P[j])]-f1[Pos(P[j])]))%PHIMOD;
if (f1[i]<0) f1[i]+=PHIMOD;
if (f[i]<0) f[i]+=PHIMOD;
}
}
ans=mul(ans,ksm(2,f[Pos(n)]),MOD);
}
【51nod1965】奇怪的式子的更多相关文章
- [51nod1965]奇怪的式子
noteskey 怎么说,魔性的题目...拿来练手 min_25 正好...吧 首先就是把式子拆开来算贡献嘛 \[ANS=\prod_{i=1}^n \sigma_0(i)^{\mu(i)} \pro ...
- 51nod1965. 奇怪的式子(min_25筛)
题目链接 http://www.51nod.com/Challenge/Problem.html#!#problemId=1965 题解 需要求的式子显然是个二合一形式,我们将其拆开,分别计算 \(\ ...
- 【51NOD1965】奇怪的式子 min_25筛
题目描述 给你\(n\),求 \[ \prod_{i=1}^n{\sigma_0(i)}^{i+\mu(i)} \] 对\({10}^{12}+39\)取模. \(\sigma_0(i)\)表示约数个 ...
- 51NOD1965:奇怪的式子
传送门 拆开变成 \[\prod_{i=1}^{n}\sigma_0(i)^{\mu(i)}\prod_{i=1}^{n}\sigma_0(i)^{i}\] 考虑 \(\prod_{i=1}^{n}\ ...
- 51nod 1965 奇怪的式子 —— min_25筛
题目:http://www.51nod.com/Challenge/Problem.html#!#problemId=1965 推式子就同这里:https://www.cnblogs.com/yoyo ...
- 51nod 1965 奇怪的式子——min_25筛
题目:http://www.51nod.com/Challenge/Problem.html#!#problemId=1965 考虑 \( \prod_{i=1}^{n}\sigma_0^i \) \ ...
- light oj 1236 分解质因数
题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70017#problem/H 题意:求满足1<=i<=j<=n ...
- BZOJ 1045 糖果传递
奇怪的式子.最后发现取中位数. #include<iostream> #include<cstdio> #include<cstring> #include< ...
- BZOJ3456城市规划
题目描述 刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了.刚才说过, 阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通.为了 ...
随机推荐
- katalon系列十:Katalon Studio自定义关键字之拖拽
Katalon Studio自带关键字“Drag And Drop To Object”,可以在这个网站实践:http://jqueryui.com/droppable/#default 不过“Dra ...
- java计算工龄
计算工龄原则:若是2000-10-12作为开始工作时间,则到下一年的2001-10-13算为一年.有个bug,不满一年的工龄是错误的. import java.util.Date;import jav ...
- python学习笔记01 --------------hello world 与变量。
1.第一个程序: print('hello world') 输出结果: hello world 2.变量 2.1 变量的作用: 把程序运算的中间结果临时存到内存里,以备后面的代码继续调用. 2.2 变 ...
- 【探路者】Alpha发布用户使用报告
预期统计用户使用数量:13人. 博文内容:1用户列表.2评论列表.3统计与总结 1用户列表: 二.评论内容 用户1:1不够好看.2不应该是中国地图为背景,蛇头是人物头像的么?(那是宣传片,不是预览图) ...
- snprintf vs sprintf
#include <stdio.h> int printf(const char *format, ...); int fprintf(FILE *stream, const char * ...
- c# 捕获一般获取不到的异常
1.主函数入口加异常事件,代码例如: /// <summary> /// 应用程序的主入口点. /// </summary> [STAThread] static void M ...
- CentOS 7 安装 MySql 8
1-安装 CentOS 7 2-安装 NETCORE SDK SDK 安装文档:https://dotnet.microsoft.com/download/linux-package-m ...
- SGU 126 Boxes(模拟题|二进制)
Translate:Sgu/126 126. 盒子 time limit per test: 0.5 sec. memory limit per test: 4096 KB 有两个盒子. 第一个盒子里 ...
- 缓存-MemoryCache Class
这是使用MemoryCache缓存的一个例子. private void btnGet_Click(object sender, EventArgs e) { ObjectCache cache = ...
- [codecademy]css
Great work! You've learned the basics of CSS structure and syntax. We'll continue to build on these ...