随(rand) (概率dp)
来源:互联网 发布:淘宝可以延长几天收货 编辑:程序博客网 时间:2024/06/07 12:05
9.23
思路:
考察概率和期望的求解,矩阵乘法,原根的性质,循环矩阵的性质,倍增优化DP.
首先需要注意到虽然n可以达到10^5,但相同数字可以合并考虑,只需要考虑mod个不同的数字及选择它们的概率.
第1个测试点:mod=2,则n个数字都是1,直接输出1即可.
第2个测试点:每次乘上去的数字只有一种选择,快速幂即可.
第3,4,5个测试点:定义f[i][j]表示i次操作后x的数值为j的概率.直接转移,复杂度O(m*mod^2)
第6,7,8个测试点:第3,4,5个测试点中的DP转移可以转化为矩阵乘法形式,利用矩阵快速幂进行优化,复杂度O(mod^3*logm)
第9,10个测试点(标算):利用原根进行转化,则乘法转化为加法,f[i][j]表示i次操作后x取模后等于原根的j次方的概率.指数需要对(mod-1)取模.这样转化一下我们发现转移还是矩阵的形式,而且是循环矩阵的形式.循环矩阵快速幂,复杂度O(mod^2*logm)
另一种标算:定义f[i][j]表示i次操作后变成原根的j次方的概率.求出g[i][j]表示2^i次操作后变成原根的j次方的概率.倍增的思想求出f[m][]这个数组.也是O(mod^2*logm)
更加优越的算法:本质上我们要做的是循环卷积,可以使用fft.但本题的模数使得fft较为不方便..
#include <cstdio>#include <iostream>#define MOD 1000000007#define N 1005using namespace std;int n, m, mod, mod2, rt;int pw[N], glog[N];int cnt[N];int P[33][N], f[2][N];int qpow(int a, int x, int mod){ int ans = 1; for( ; x; x>>=1, a=a*1ll*a%mod) if(x & 1) ans = ans * 1ll * a % mod; return ans;}int getroot(int x){ for(int i=1; i<=x; ++i){ int tmp = 1; bool flag = true; for(int j=1; j<x-1; ++j){ tmp = tmp * 1ll * i % mod; if(tmp == 1){ flag = false; break; } } if( flag ) return i; }}int main(){ freopen ("rand.in", "r", stdin); freopen ("rand.out", "w", stdout); scanf("%d%d%d", &n, &m, &mod); rt = getroot(mod); pw[0] = 1; for(int i=1; i<=mod; ++i){ pw[i] = pw[i-1] * 1ll * rt % mod; }//pw[i]记录 rt^i mod 的 ans for(int i=0; i<mod-1; ++i) glog[pw[i]] = i; mod2 = mod - 1; for(int i=1; i<=n; ++i){ int x; scanf("%d", &x); cnt[glog[x]]++; } int invn = qpow(n, MOD-2, MOD);//a*(b^(10^9+5))模10^9+7 10^9+7是P 10^9+5是P-2 所以也就是求a * invb for(int i=0; i<mod2; ++i){ P[0][i] = invn * 1ll * cnt[i] % MOD;//2^0次操作之后 同余于rt^i的概率 } for(int i=1; i<=32; ++i){ for(int j=0; j<mod2; ++j){ for(int k=0; k<mod2; ++k){ P[i][(j+k)%mod2] = ( P[i][(j+k)%mod2] + P[i-1][j] * 1ll * P[i-1][k] % MOD ) % MOD; } } } int p = 0; f[0][0] = 1;//初始值为1 for(int i=0; m; m>>=1, ++i){ if(m & 1){ p ^= 1; for(int j=0; j<mod2; ++j) f[p][j] = 0;//滚动数组清零 for(int j=0; j<mod2; ++j){ for(int k=0; k<mod2; ++k){ f[p][(j+k)%mod2] = ( f[p][(j+k)%mod2] + f[p^1][j] * 1ll * P[i][k] % MOD ) % MOD; }//m次操作之后 同余于rt^i的概率 } } } for(int j=0; j<mod2; ++j) f[0][j] = f[p][j]; int ans = 0; for(int i=0; i<mod2; ++i){ ans = (ans + f[0][i] * 1ll * pw[i] % MOD) % MOD;//概率乘权值 } printf("%d\n", ans); return 0;}
阅读全文
0 0
- 随(rand) (概率dp)
- Liu_runda 的简单题 随(rand) 倍增优化 概率DP
- poj3071(概率DP)
- codeforces148D(概率DP)
- poj2151(概率DP)
- hdu4870(概率dp)
- hdu3853(概率dp)
- zoj3822(概率DP)
- Codeforce148D(概率dp)
- 概率统计(DP)
- hdu4815 (概率DP)
- hdu5001(概率dp)
- hdu4405(概率dp)
- zoj3822(概率dp)
- zoj3329(概率dp)
- hdu5001(概率dp)
- POJ2096(概率dp)
- Activation (概率DP)
- linux node环境配置
- 用jquery简单实现弹幕效果
- 【GDOI2018模拟9.23】动态图
- 点亮LED灯
- python apriori
- 随(rand) (概率dp)
- request参数绑定
- [深度学习] (2):实现简单的线性回归(使用TensorFlow优化)
- ubuntu16.04 64位安装tensorflow+cuda8.0+cudnn7.0
- libuv的浅薄理解
- centos6 nat路由转发
- ubuntu中使用apt-get安装zbar
- 原型模式
- ITON