[ Luogu 4917 ] 天守阁的地板
\(\\\)
\(Description\)
定义二元函数\(F(x,y)\)表示,用 \(x\times y\) 的矩形不可旋转的铺成一个任意边长的正方形,所需要的最少的矩形个数。
现在\(T\)组询问,每次给出一个\(N\),求\(\prod_{i=1}^N\prod_{j=1}^N F(i,j)\) 模\(19260817\)的值。
- \(N\in[1,10^6],T\in[1,10^3]\)
\(\\\)
下面的表述中用\([x,y]\)表示\(Lcm(x,y)\),用\((x,y)\)表示\(Gcd(x,y)\)。
\(\\\)
\(Solution1:\text O(N+T\sqrt NlogN)\)
出题人的做法。对于\(N\)更大一些,\(T\)较小的情况表现比较优秀。
考虑一个边长为\(x\times y\)的矩形铺成的最小正方形的边长,因为不可旋转,所以答案为\([x,y]\)。
那么用这种矩形铺出这个正方形需要的块数就是\(\frac{[x,y]^2}{xy}\),总面积除以单块面积嘛。
然后所求可以形式化的写出:
\]
上面的转化是基于以下定理:
\]
然后考虑对于每一次询问的\(N\),如何快速求出答案。
\(\\\)
首先将分母分子分开考虑,对于分子,有:
\]
具体证明不太好说,大致是每一次循环到的\(i\)都要被乘上\(N\)次,手玩一下差不多就懂了。
这部分显然可以\(\text O(N)\)求\(N!\),然后再每一个数都算一个快速幂即可,预处理复杂度\(\text O(Nlog(2N))\)。
\(\\\)
然后考虑分子部分如何求,首先先将平方提出来:
\]
因为是连乘显然合理。
然后括号里的东西显然可以根据\(Gcd\)的值分情况讨论:
\]
然后根据仪仗队的解法,我们知道有:
\]
然后可以线性筛求\(\varphi\),预处理\(\varphi\)的前缀和,查询这个指数就是\(\text O(1)\)的了,预处理复杂度\(\text O(N)\)。
我们设\(g[x]\)表示:
\]
那么现在需要解决的式子是
\]
然后注意到这个东西可以除法分块,考虑对于一个\(\lfloor\frac Nd\rfloor\)相同的区间\([L,R]\),答案为
\]
然后连乘积部分可以用阶乘相除的方法求解,因为模意义下我们还需要处理每一个阶乘的逆元。
然后快速幂求一下,在套回去平方一下,再求个逆元乘上\((N\ !)^{2N}\)就是答案了。
单次处理除法分块+快速幂复杂度\(\text O(\sqrt NlogN)\),总复杂度\(\text O(N+T\sqrt NlogN)\)
\(\\\)
\(Code1:\text O(N+T\sqrt NlogN)\)
#include<cmath>
#include<cctype>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define R register
#define gc getchar
#define N 1000010
#define mod 19260817ll
using namespace std;
typedef long long ll;
ll g[N]={1,1},phi[N]={0,1},prm[N];
ll fac[N]={0,1},fac2[N]={0,1},inv[N]={1};
inline int rd(){
int x=0; bool f=0; char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return f?-x:x;
}
inline ll qpow(ll x,ll t){
ll res=1ll;
while(t){
if(t&1) (res*=x)%=mod;
(x*=x)%=mod; t>>=1;
}
return res;
}
inline void init(){
for(R int i=2;i<N;++i){
g[i]=1;
if(!phi[i]){phi[i]=i-1;prm[++prm[0]]=i;}
for(R int j=1,k;j<=prm[0]&&(k=prm[j]*i)<N;++j)
if(i%prm[j]) phi[k]=phi[i]*phi[prm[j]];
else{phi[k]=phi[i]*prm[j];break;}
}
for(R ll i=2;i<N;++i) fac[i]=fac[i-1]*i%mod,phi[i]+=phi[i-1];
for(R int i=2;i<N;++i) fac2[i]=qpow(fac[i],(i<<1));
for(R int i=1;i<N;++i) inv[i]=qpow(fac[i],mod-2);
}
inline void work(){
ll n=rd(),ans=1ll;
for(R ll l=1,t,r;l<=n;l=r+1){
t=n/l; r=n/t;
(ans*=qpow(fac[r]*inv[l-1]%mod,phi[t]*2-1))%=mod;
}
ans=(qpow(ans,(mod-2)<<1)*fac2[n])%mod;
printf("%lld\n",ans);
}
int main(){
init();
int t=rd();
while(t--) work();
return 0;
}
\(\\\)
\(Solution2:\text O(N\sqrt NlogN+T)\)
我的做法。卡着时限也就过了,对\(T\)大的时候表现会很优秀。
继续考虑这个式子:
\]
分子部分不变,还是那么预处理,分母我有一个不同的做法。
首先还是把平方套在外面:
\]
然后平方里面的部分解法就不太一样了,设一个\(g[n]\)表示:
\]
第一个等号是定义,第二个等号理解为,设\((i,n)=d\),那么这样的数对有\(\varphi(\lfloor\frac{N}{d}\rfloor)\)个,因为除掉\(d\)两数应该互质。
然后类似仪仗队的做法,把求和扩展到求积,那么考虑将下三角矩阵的积求出来,答案是
\]
然后整个矩阵的积是下三角的平方除以对角线,对角线的积是\(\prod(i,i)=N\ !\),所以整个矩阵的积等于
\]
回到所求,有
\]
复杂度预处理 \(g\) 数组\(\text O(N\sqrt NlogN)\),分别代表质因数分解和快速幂的复杂度。
其他线性筛、求阶乘、求逆元等的复杂度都不会太高,之后显然每一个数的答案都可以\(\text O(1)\)得到了。
\(\\\)
\(Code2:\text O(N\sqrt NlogN+T)\)
#include<cmath>
#include<cctype>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define R register
#define gc getchar
#define N 1000010
#define mod 19260817ll
using namespace std;
typedef long long ll;
ll g[N]={1},fac[N]={0,1};
int phi[N]={0,1},prm[N];
inline int rd(){
int x=0; bool f=0; char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return f?-x:x;
}
inline ll qpow(ll x,ll t){
ll res=1ll;
while(t){
if(t&1) (res*=x)%=mod;
(x*=x)%=mod; t>>=1;
}
return res;
}
inline void init(){
for(R int i=2;i<N;++i){
if(!phi[i]){phi[i]=i-1;prm[++prm[0]]=i;}
for(R int j=1,k;j<=prm[0]&&(k=prm[j]*i)<N;++j)
if(i%prm[j]) phi[k]=phi[i]*phi[prm[j]];
else{phi[k]=phi[i]*prm[j];break;}
}
for(R ll i=2;i<N;++i) fac[i]=fac[i-1]*i%mod;
for(R int i=2;i<N;++i) fac[i]=qpow(fac[i],(i<<1)+2);
for(R int i=1,r;i<N;++i){
r=sqrt(i); g[i]=1ll;
for(R int j=1;j<=r;++j)
if(i%j==0){
(g[i]*=qpow(j,phi[i/j]))%=mod;
if(i/j!=j) (g[i]*=qpow(i/j,phi[j]))%=mod;
}
(g[i]*=g[i-1])%=mod;
}
for(R int i=1;i<N;++i) g[i]=qpow(g[i],(mod-2)*4);
for(R int i=1;i<N;++i) (g[i]*=fac[i])%=mod;
}
int main(){
init();
int t=rd();
while(t--) printf("%lld\n",g[rd()]);
return 0;
}
\(\\\)
\(Solution3:\text O(N\times lnN\times logN+T)\)
优化一下第二个做法。
依次考虑每一个数对每一个 \(g\) 的贡献,所以一个数 \(i\) 能做贡献的数有\(\lfloor\frac Ni\rfloor\)个,直接暴力乘更新 \(g\) 就好。
此时复杂度神奇的降到了调和级数,也就是\(ln N\)。
\(\\\)
\(Code3:\text O(N\times lnN\times logN+T)\)
#include<cmath>
#include<cctype>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define R register
#define gc getchar
#define N 1000010
#define mod 19260817ll
using namespace std;
typedef long long ll;
ll g[N]={1,1},fac[N]={0,1};
int phi[N]={0,1},prm[N];
inline int rd(){
int x=0; bool f=0; char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return f?-x:x;
}
inline ll qpow(ll x,ll t){
ll res=1ll;
while(t){
if(t&1) (res*=x)%=mod;
(x*=x)%=mod; t>>=1;
}
return res;
}
inline void init(){
for(R int i=2;i<N;++i){
g[i]=1;
if(!phi[i]){phi[i]=i-1;prm[++prm[0]]=i;}
for(R int j=1,k;j<=prm[0]&&(k=prm[j]*i)<N;++j)
if(i%prm[j]) phi[k]=phi[i]*phi[prm[j]];
else{phi[k]=phi[i]*prm[j];break;}
}
for(R ll i=2;i<N;++i) fac[i]=fac[i-1]*i%mod;
for(R int i=2;i<N;++i) fac[i]=qpow(fac[i],(i<<1)+2);
for(R int i=1;i<N;++i)
for(R ll j=1;j*(ll)i<(ll)N;++j) (g[j*i]*=qpow(i,phi[j]))%=mod;
for(R int i=1;i<N;++i) (g[i]*=g[i-1])%=mod;
for(R int i=1;i<N;++i) g[i]=qpow(g[i],(mod-2)*4);
for(R int i=1;i<N;++i) (g[i]*=fac[i])%=mod;
}
int main(){
init();
int t=rd();
while(t--) printf("%lld\n",g[rd()]);
return 0;
}
[ Luogu 4917 ] 天守阁的地板的更多相关文章
- Luogu 4917 天守阁的地板(莫比乌斯反演+线性筛)
既然已经学傻了,这个题当然是上反演辣. 对于求积的式子,考虑把[gcd=1]放到指数上.一通套路后可以得到∏D∏d∏i∏j (ijd2)μ(d) (D=1~n,d|D,i,j=1~n/D). 冷静分析 ...
- 【洛谷】4917:天守阁的地板【欧拉函数的应用】【lcm与gcd】【同除根号优化】
P4917 天守阁的地板 题目背景 在下克上异变中,博丽灵梦为了找到异变的源头,一路打到了天守阁 异变主谋鬼人正邪为了迎击,将天守阁反复颠倒过来,而年久失修的天守阁也因此掉下了很多块地板 异变结束后, ...
- luogu4917天守阁的地板
https://www.zybuluo.com/ysner/note/1317548--- 题面 给出\(n\),用所有长为\(a\).宽为\(b\)\((1\leq a,b\leq n)\)的长方形 ...
- 省选前的th题
沙茶博主终于整完了知识点并学完了早该在NOIP之前学的知识们 于是终于开始见题了,之前那个奇怪的题单的结果就是这个了 题目按沙茶博主的做题顺序排序 个人感觉(暂时)意义不大的已被自动忽略 洛谷 491 ...
- X000011
P1890 gcd区间 \(\gcd\) 是满足结合律的,所以考虑用 ST 表解决 时间复杂度 \(O((n\log n+m)\log a_i)\) 考虑到 \(n\) 很小,你也可以直接算出所有的区 ...
- Hihocoder 太阁最新面经算法竞赛18
Hihocoder 太阁最新面经算法竞赛18 source: https://hihocoder.com/contest/hihointerview27/problems 题目1 : Big Plus ...
- hihoCoder太阁最新面经算法竞赛15
hihoCoder太阁最新面经算法竞赛15 Link: http://hihocoder.com/contest/hihointerview24 题目1 : Boarding Passes 时间限制: ...
- Luogu 魔法学院杯-第二弹(萌新的第一法blog)
虽然有点久远 还是放一下吧. 传送门:https://www.luogu.org/contest/show?tid=754 第一题 沉迷游戏,伤感情 #include <queue> ...
- luogu p1268 树的重量——构造,真正考验编程能力
题目链接:http://www.luogu.org/problem/show?pid=1268#sub -------- 这道题费了我不少心思= =其实思路和标称毫无差别,但是由于不习惯ACM风格的题 ...
随机推荐
- MongoDB小结14 - find【查询条件$lt $lte $gt $gte】
$lt $lte $gt $gte 以上四个分别表示为:< . <= . > . >= . 通常的做法是将他们组合起来,以便查找一个范围. 比如,查询年龄在18到25岁(含)的 ...
- owncloud
owncloud https://dl.iuscommunity.org/pub/ius/stable/CentOS/6/x86_64/ [root@n1 ~]# rpm -Uvh ius-relea ...
- prototype与几个循环的心得
<一>prototypeprototype其实是函数的一个属性,并且只有函数有这个属性,这个属性就是给函数增加函数或者属性的,比如写一个function one(){},那么one.pro ...
- linux c 获取当前执行进程总数
获取当前执行进程总数的命令为: ps auxw | wc -l 获取当前执行进程总数的源代码例如以下: #include <stdio.h> #include <stdlib.h&g ...
- hdu1115 Lifting the Stone(几何,求多边形重心模板题)
转载请注明出处:http://blog.csdn.net/u012860063 题目链接:pid=1115">http://acm.hdu.edu.cn/showproblem.php ...
- JavaScript图片裁剪
1.jquery 图片裁剪库选择 Jcrop:http://deepliquid.com/content/Jcrop.html imgareaselect:http://odyniec.net/pro ...
- 洛谷 P1759 通天之潜水
P1759 通天之潜水 19通过 65提交 题目提供者lych 标签动态规划洛谷原创 难度普及/提高- 提交该题 讨论 题解 记录 最新讨论 暂时没有讨论 题目背景 直达通天路·小A历险记第三篇 题目 ...
- Ajax 之 DWR
DWR是开源框架,类似于hibernate.借助于DWR,开发人员无需具备专业的JavaScript知识就可以轻松实现Ajax,是Ajax更平民化. 添加jar包 dwr.jar common ...
- HttpClient-03Http状态管理
最初,Http被设计成一个无状态的,面向请求/响应的协议,所以它不能在逻辑相关的http请求/响应中保持状态会话.由于越来越多的系统使用http协议,其中包括http从来没有想支持的系统,比如电子商务 ...
- 同一个站点下,兼容不同版本的JQuery
https://stackoverflow.com/questions/1566595/can-i-use-multiple-versions-of-jquery-on-the-same-page Y ...