题解P4917 天守阁的地板

题目:P4917 天守阁的地板  

双倍经验:P5221 Product  

先说这题怎么做。
首先我们知道可以铺的地板块数为lcm(a,b)*lcm(a,b)/(a*b)=a*b/gcd(a,b)*lcm(a,b)/(a*b)=lcm(a,b)/gcd(a,b)
然后就可以愉快的莫反了。博主惨兮兮不会用LaTeX写数学公式,所以。。搬了一张图。
原文章 因为这位大佬和我的做法很相似,所以借用了他的题解表达出我的想法。
于是我开开心心地做了一下,十分暴力地对于每个n求一遍,喜提60分的佳绩。。。
但我把这份代码改了一下交到P5221 Product,拿到了满分。
 1 #include<stdio.h>
 2 #define it register int
 3 #define il inline
 4 const int mod=104857601;
 5 const int N=1000005;
 6 typedef long long ll;
 7 int n,mu[N],p[N/10+2],cnt;
 8 bool isp[N];
 9 ll ans;
10 il void mui(){
11     mu[1]=1;
12     register long long x;
13     for(it i=2;i<N;++i){
14         if(!isp[i]) p[++cnt]=i,mu[i]=-1;
15         for(it j=1;(x=1ll*i*p[j])<N&&j<=cnt;++j){
16             isp[x]=1;
17             if(!(i%p[j])) break;
18             mu[x]=-mu[i];
19         }
20     }
21     for(it i=2;i<N;++i) mu[i]+=mu[i-1];
22 }
23 il void ksm(ll x,it l,ll &now){
24     now=1;
25     while(l){
26         if(l&1) now=1ll*now*x%mod;
27         x=x*x%mod,l>>=1;
28     }
29 }
30 il void cal(it x,ll &now){
31     now=0;for(it l=1,r;l<=x;l=r+1) r=x/(x/l),now=(now+1ll*(x/l)*(x/l)%(mod-1)*(mu[r]-mu[l-1]+mod-1)%(mod-1))%(mod-1);
32 }
33 int main(){
34     scanf("%d",&n),mui();ans=1;
35     for(it i=2;i<=n;++i) ans=ans*i%mod;
36     ksm(ans,n<<1,ans);
37     ll now1=0,now2=0,s1=1,s2=1,now3=0;
38     it i=1,j=1;
39     for(it l=1,r;l<=n;l=r+1){
40         r=n/(n/l);
41         while(i<=l-1) s1=s1*i%mod,++i;
42         while(j<=r) s2=s2*j%mod,++j;
43         ksm(s2,mod-2,now2),cal(n/l,now3),ksm(now2*s1%mod,2*now3,now2),ans=ans*now2%mod; 
44     }
45     printf("%lld",ans); 
46     return 0;
47 }
View Code
思考了一下,如果对于每个n求一遍,O(T*n)不超时就怪了。。
那么怎么办呢?最好是可以预处理,然后在sqrt(n)时间内完成
我们再看一眼分母,发现分母可以再化简化简:
 
我们可以枚举gcd,然后把式子化简成这样:
分子分母都有(n!),把分子里的提上去。于是就可以愉快滴敲代码啦。
 1 #include<stdio.h>
 2 #define it register int
 3 #define il inline
 4 const int N=1000005;
 5 const int mod=19260817;
 6 typedef long long ll;
 7 int mu[N],p[N],T,cnt,n;
 8 bool isp[N];
 9 ll ans,fac[N],o[N],ph[N];
10 il void ksm(ll x,ll l,ll &now){
11     now=1;
12     while(l){
13         if(l&1) now=now*x%mod;
14         x=x*x%mod,l>>=1;
15     }
16 }
17 il void cal(it x,ll &now){
18     now=0;for(it l=1,r;l<=x;l=r+1) r=x/(x/l),now=(now+1ll*(x/l)*(x/l)*(mu[r]-mu[l-1]+mod-1)%(mod-1))%(mod-1);
19 }
20 il void phi(){
21     ph[1]=1;
22     register long long x;
23     for(it i=2;i<N;++i){
24         if(!isp[i]) ph[i]=i-1,p[++cnt]=i;
25         for(it j=1;(x=1ll*i*p[j])<N&&j<=cnt;++j){
26             isp[x]=1;
27             if(!(i%p[j])) {ph[x]=1ll*ph[i]*p[j];break;}
28             ph[x]=1ll*ph[i]*ph[p[j]];
29         }
30     }
31     for(it i=2;i<N;++i) ph[i]=(ph[i]+ph[i-1])%(mod-1);            
32 }
33 namespace io {
34     const int SIZE = (1 << 21) + 1;
35     char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55];
36     int f, qr;
37 #define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
38     inline void flush () {fwrite (obuf, 1, oS - obuf, stdout);oS = obuf;}
39     template <class I>
40     inline void fr (I &x) {
41         for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;
42         for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15);
43         x *= f;
44     }
45     struct Flusher_ {~Flusher_() {flush();}} io_flusher_;
46 }
47 using io :: fr; 
48 int main(){     
49     phi();
50     fr(T);
51     fac[0]=fac[1]=1;for(it i=2;i<=1000000;++i) fac[i]=1ll*fac[i-1]*i%mod; 
52     ll now1,now2;
53     while(T--){
54         fr(n);
55         ans=1;
56         for(it l=1,r;l<=n;l=r+1){
57             r=n/(n/l),ksm(fac[l-1],mod-2,now1),ksm(fac[r]*now1%mod,ph[n/l]%mod,now2),ans=ans*now2%mod; 
58         } 
59         ksm(fac[n],(n<<1|1)+1,now1),ksm(ans,mod-5,ans);//ans^4的逆元  
60         printf("%lld\n",ans*now1%mod);
61     }
62     return 0;
63 }
View Code

 

 
posted @ 2019-10-24 09:01  kylin_xy  阅读(94)  评论(0编辑  收藏  举报