zoukankan      html  css  js  c++  java
  • 题解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
    ",ans*now1%mod);
    61     }
    62     return 0;
    63 }
    View Code
     
  • 相关阅读:
    卡片选项页面 JTabbedPane 的使用
    下拉列表 JComboBox 的使用
    单选按钮 JradioButton 和复选框 JcheckBox 的使用
    标签 JLable 类
    文本区 JTextArea 的使用
    密码框JPasswordField 的使用
    JHDU 2601 An easy problem (数学 )
    HDU 2554 N对数的排列问题 ( 数学 )
    LaTeX初识 新手入门 Texlive和Texmaker学习
    [leetcode-387-First Unique Character in a String]
  • 原文地址:https://www.cnblogs.com/Kylin-xy/p/11730240.html
Copyright © 2011-2022 走看看