• 随 (rand) (dp,原根,矩阵/倍增优化)


    随 (rand):

      题干:

      题解:

        对于$10\%$的数据mod=2,a[i]必定为1,直接输出1.

        对于另$10\%$的数据n=1,输出$ a[1]^m\%mod $ 注意模mod而非$1e9+7$。

        对于$50\%$的数据,我们考虑dp,

          设$ f[i][j] $为i次操作后结果为j的方案数,

          易得转移方程为:$ f[i][j*a[k]\%mod]=sumlimits f[i-1][j] $(考场上想到的sb DP)

          但$ O(n*m*mod) $的复杂度令人望而却步,并不能多得分。

          于是考虑优化,观察得$mod<=300$而$n<=100000$,想到类似离散化的思路,

          用一个数组$c[i]$记录第$i$数出现的次数

          转移方程式变为:$ f[i][j*a[k]\%mod]=sumlimits f[i-1][j]*c[k] $

          时间复杂度变为$ O(m*mod^2) $,期望得分50pts。

        对于$ 100\% $的数据,我们考虑优化,

          方法一:矩阵快速幂+原根优化(然而蒟蒻并不会)附上wd大神博客

          方法二:倍增优化,

            回过头来再看刚才的DP式子,我们可得:$ f[i+q][j*a[k]\%mod]=f[i][j]*f[q][k] $

            同样可得:$ f[2*i][j*k\%mod]=f[i][j]*f[i][k] $

            于是我们可以在$ O(logm) $的时间求出 $f[2^1],f[2^2],f[2^3]cdots,f[2^n]  (2^n<= m< 2^{n+1}) $

            所以我们可以使用快速幂的思想,将m二进制拆分,下附普通快速幂模板:

    ll qpow(ll x,ll y,ll mod)
    {
    	ll ans=1;
    	while(y){
    		if(y&1)ans=ans*x%mod;
    		x=x*x%mod;y>>=1;
    	}
    	return ans;
    }
    

            将其中y变为m,x变为f数组,ans为g数组。

            $f[i][j]$数组含义也变为操作$2^i$次,结果为$j$的方案数。

            而$g[i][j]$数组为操作$2^1+2^2+2^3+cdots+2^i$次,结果为$j$的方案数。

            所以$ f[i][j*k\%mod]=sumlimits_{j=1}^{mod-1}sumlimits_{k=1}^{mod-1}f[i-1][j]*f[i-1][k] $

              $ g[i][j*k\%mod]=sumlimits_{j=1}^{mod-1}sumlimits_{k=1}^{mod-1}g[i-1][j]*f[i][k] $

            还有最后一个问题:内存

            当前我们的空间复杂度为:$ O(logm*mod) $,而f,g数组都只与上一个状态有关,显然可用滚动数组,最后的空间复杂度为$O(2*mod)$,时间复杂度为$O(mod^2logm)$。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cmath>
     5 #include<algorithm>
     6 using namespace std;
     7 #define R register
     8 #define ll long long
     9 inline ll read(){
    10     ll aa=0;R int bb=1;char cc=getchar();
    11     while(cc<'0'||cc>'9')
    12         {if(cc=='-')bb=-1;cc=getchar();}
    13     while(cc>='0'&&cc<='9')
    14         {aa=(aa<<1)+(aa<<3)+(cc^48);cc=getchar();}
    15     return aa*bb;
    16 }
    17 const int p=1e9+7;
    18 const int N=1005;
    19 ll qpow(ll x,ll y,ll mod)
    20 {
    21     ll ans=1;
    22     while(y){
    23         if(y&1)ans=ans*x%mod;
    24         x=x*x%mod;y>>=1;
    25     }
    26     return ans;
    27 }
    28 ll n,mod,m,tmp=0,cur=0;
    29 ll ans,f[2][N],g[2][N];
    30 inline void split(int y)
    31 {
    32     while(y){
    33         if(y&1){
    34             memset(g[cur^1],0,sizeof(g[cur^1]));
    35             for(R int i=1;i<mod;++i)
    36                 for(R int j=1;j<mod;++j)
    37                     g[cur^1][i*j%mod]=(g[cur^1][i*j%mod]+f[tmp][i]*g[cur][j]%p)%p;
    38             cur^=1;
    39         }
    40         y>>=1;
    41         memset(f[tmp^1],0,sizeof(f[tmp]));
    42         for(R int i=1;i<mod;++i){
    43             for(R int j=1;j<mod;++j)
    44                 f[tmp^1][i*j%mod]=(f[tmp^1][i*j%mod]+f[tmp][i]*f[tmp][j])%p;
    45         }
    46         tmp^=1;
    47     }
    48 }
    49 int main()
    50 {
    51     n=read();m=read();mod=read();
    52     if(mod==2){puts("1");return 0;}
    53     if(n==1){
    54         int x=read();
    55         ans=qpow(x,m,mod);
    56         printf("%lld
    ",ans%p);
    57         return 0;
    58     }
    59     for(R int i=1;i<=n;++i)
    60         ++f[0][read()];
    61     g[0][1]=1;
    62     split(m);
    63     for(R int i=1;i<=mod;++i)
    64         ans=(ans+g[cur][i]*i%p)%p;
    65     ans=1ll*ans*qpow(n,m*(p-2),p)%p;
    66     printf("%lld
    ",ans);
    67     return 0;
    68 }
    然后我们就开心的AC了
  • 相关阅读:
    跨浏览器的事件处理程序(javascript高级程序设计第二版第十二章)
    json
    html5 本地存储Web Storage
    sicily 6497. 字符统计
    sicily 6415. linear correlation
    sicily 1154. Easy sort
    sicily 6496. 二维数组
    sicily 6423. 反向输出数字
    sicily 1636. show me the money
    sicily 1324. Score
  • 原文地址:https://www.cnblogs.com/toot-wjh/p/11258119.html
Copyright © 2020-2023  润新知