这个题的题解并不想写……一个写的很详细的blog

第1个测试点:mod=2,a[i]<mod(仔细看题),则n个数字都是1,直接输出1即可.

第2个测试点:每次乘上去的数字只有一种选择,快速幂即可.

第3,4,5个测试点:定义f[i][j]表示i次操作后x的数值为j的概率.直接转移,复杂度O(m*mod^2)

         f[][]=;
for(int i=;i<m;i++)
for(int j=;j<mod;j++)
for(int k=;k<mod;k++)//这里不要枚举n啊,可以先处理出来每个数出现的概率
f[i+][j*k%mod]=(f[i+][j*k%mod]+f[i][j]*v[k]%p)%p;

第6,7,8个测试点:第3,4,5个测试点中的DP转移可以转化为矩阵乘法形式,利用矩阵快速幂进行优化,复杂度O(mod^3*logm)矩阵快速幂优化dp见--->这里

 #include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define int LL
#define MAXN 100010
#define LL long long
using namespace std;
struct jz
{
LL m[][];
void clear(){memset(m,,sizeof(m));}
}base;
int n,m,mod,a[MAXN];
const int p=1e9+;
jz operator * (jz &a,jz &b)
{
jz ans;ans.clear();
for(int i=;i<mod;i++)
for(int j=;j<mod;j++)
for(int k=;k<mod;k++)
ans.m[i][j]=(ans.m[i][j]+a.m[i][k]*b.m[k][j]);
for(int i=;i<mod;i++)
for(int j=;j<mod;j++)
ans.m[i][j]%=p;
return ans;
}
jz operator ^ (jz a,int b)
{
jz ans=a;b--;
while(b)
{
if(b&)ans=ans*a;
a=a*a;
b=b>>;
}
return ans;
}
LL f[][],tem;
LL v[];
LL poww(LL a,int b,int mod)
{
LL ans=;
while(b)
{
if(b&)ans=ans*a%mod;
a=a*a%mod;
b=b>>;
}
return ans;
}
signed main()
{
// freopen("in.txt","r",stdin);
// freopen("0.out","w",stdout); cin>>n>>m>>mod;tem=poww(n,p-,p);
for(int i=;i<=n;i++)cin>>a[i],v[a[i]%mod]=(v[a[i]%mod]+tem)%p;
if(mod==){puts("");return ;}
if(n==){printf("%lld\n",poww(a[],m,mod));return ;}
if(m<=)
{
f[][]=;
for(int i=;i<m;i++)
for(int j=;j<mod;j++)
for(int k=;k<mod;k++)
f[i+][j*k%mod]=(f[i+][j*k%mod]+f[i][j]*v[k]%p)%p;
LL ans=;
for(int i=;i<mod;i++)
ans=(ans+f[m][i]*i%p)%p;
printf("%lld\n",ans%p);
}
else if(mod<=)
{
for(int j=;j<mod;j++)
for(int k=;k<mod;k++)
base.m[j*k%mod][j]=(base.m[j*k%mod][j]+v[k])%p;
base=base^m;
LL ans=;
for(int i=;i<mod;i++)
ans=(ans+base.m[i][]*i%p)%p;
printf("%lld\n",ans%p);
}
}

这里放出暴力dp和矩阵优化dp

第9,10个测试点(标算):上面那个blog讲的非常详细了(然而我并没有看懂……),总感觉这个矩阵优化dp怪怪的……

先把达哥题解放出来:

利用原根进行转化,则乘法转化为加法,f[i][j]表示i次操作后x取模后等于原根的j次方的概率.指数需要对(mod-1)取模.这样转化一下我们发现转移还是矩阵的形式,而且是循环矩阵的形式.循环矩阵快速幂,复杂度O(mod^2*logm)

然后是另一种标算(本人写的这个):

定义f[i][j]表示i次操作后变成原根的j次方的概率.求出p[i][j]表示2^i次操作后变成原根的j次方的概率.倍增的思想求出f[m][]这个数组.也是O(mod^2*logm)

     for(int i=;i<=mod-;i++)p[][i]=tem*cnt[i]%mp;//乘2^0为rt^i的概率,tem为分母的逆元,cnt为个数。
for(int i=;i<=;i++)
for(int j=;j<=mod-;j++)
for(int k=;k<=mod-;k++)
p[i][(j+k)%(mod-)]=(p[i][(j+k)%(mod-)]+p[i-][j]*p[i-][k]%mp)%mp;

然后用类似快速幂的方法就可以求出了,避免了直接理解矩阵。

 #include<iostream>
#include<cstdio>
#define MAXN 400010
#define LL long long
#define int LL
using namespace std;
const int mp=1e9+;
int n,m,mod,a[MAXN];
int xp[],cnt[];
int rt;
int p[][],f[][];
LL poww(LL a,int b,int mod)
{
LL ans=;
while(b)
{
if(b&)ans=ans*a%mod;
a=a*a%mod;
b=b>>;
}
return ans;
}
void findroot()
{
for(rt=;rt<mod;rt++)
{
bool pd=;
for(int i=;i<mod-;i++)
if(poww(rt,i,mod)==){pd=;break;}
if(pd||poww(rt,mod-,mod)!=)continue;
else break;
}
}
signed main()
{
cin>>n>>m>>mod;
findroot();int tem=poww(n,mp-,mp),x;
xp[]=;for(int i=;i<=mod;i++)xp[i]=xp[i-]*rt%mod;
for(int i=;i<=mod-;i++)a[xp[i]]=i;
for(int i=;i<=n;i++)cin>>x,cnt[a[x]]++;
for(int i=;i<=mod-;i++)p[][i]=tem*cnt[i]%mp;//乘2^0为rt^i的概率;
for(int i=;i<=;i++)
for(int j=;j<=mod-;j++)
for(int k=;k<=mod-;k++)
p[i][(j+k)%(mod-)]=(p[i][(j+k)%(mod-)]+p[i-][j]*p[i-][k]%mp)%mp;
f[][]=;
for(int k=;m;m/=,k++)
if(m&)
{
for(int i=;i<=mod-;i++)f[][i]=;
for(int i=;i<=mod-;i++)
for(int j=;j<=mod-;j++)
f[][(j+i)%(mod-)]=(f[][(j+i)%(mod-)]+f[][i]*p[k][j]%mp)%mp;
for(int i=;i<=mod-;i++)f[][i]=f[][i];
}
LL ans=;
for(int i=;i<=mod-;i++)ans=(ans+f[][i]*xp[i]%mp)%mp;
printf("%lld\n",ans);
}

完整代码

更加优越的算法(???):本质上我们要做的是循环卷积,可以使用fft.但本题的模数使得fft较为不方便..

HZOJ 随的更多相关文章

  1. hzoj 2301(莫比乌斯反演)

    题意 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公 数. 思路: 与先前的那个相比,这次a,c并不一定 ...

  2. HZOJ 单

    两个子任务真的是坑……考试的时候想到了60分的算法,然而只拿到了20分(各种沙雕错,没救了……). 算法1: 对于测试点1,直接n遍dfs即可求出答案,复杂度O(n^2),然而还是有好多同学跑LCA/ ...

  3. 20191102 「HZOJ NOIP2019 Round #12」20191102模拟

    先开坑. md原题写挂我也真是... 100+20+10 白夜 打表大法吼 显然,不在环上的点对答案的贡献是 \((k-cycle)^{k-1}\) . 打表得到环上的递推式,矩阵一下乘起来就好了. ...

  4. 20191004 「HZOJ NOIP2019 Round #9」20191004模拟

    综述 第一次 rk1 ,激动. 题目是 COCI 18/19 Round #1 的三至五题. 得分 \(100+100+20\) \(\mathrm{cipele}\) 问题描述 HZOJ1313 题 ...

  5. 20191003 「HZOJ NOIP2019 Round #8」20191003模拟

    综述 试题为常州集训2019SCDay2 得分\(100+30(0)+28\) 时之终结 问题描述 HZOJ1310 题解 构造题. 发现部分分有一档是 \(Y\) 是 \(2^x\) ,于是自然想到 ...

  6. 20190922 「HZOJ NOIP2019 Round #7」20190922模拟

    综述 这次是USACO2019JAN Gold的题目. \(\mathrm{Cow Poetry}\) 题解 因为每句诗的长度一定是\(k\),所以自然而然想到背包. 设\(opt[i][j]\)代表 ...

  7. HZOJ 20190819 NOIP模拟26题解

    考试过程: 照例开题,然后觉得三道题都挺难,比昨天难多了(flag×1),T1 dp?T2 数据结构? T3 dp?事实证明我是sb然后决定先搞T2,但是,woc,这题在说什么啊,我怎么看不懂题啊,连 ...

  8. HZOJ 20190818 NOIP模拟24题解

    T1 字符串: 裸的卡特兰数题,考拉学长讲过的原题,就是bzoj3907网格那题,而且这题更简单,连高精都不用 结论$C_{n+m}^{n}-C_{n+m}^{n+1}$ 考场上10min切掉 #in ...

  9. HZOJ 20190727 随(倍增优化dp)

    达哥T1 实际上还是挺难的,考试时只qj20pts,还qj失败 因为他专门给出了mod的范围,所以我们考虑把mod加入时间复杂度. $50\%$算法: 考虑最暴力的dp,设$f[i][j]$表示进行$ ...

  10. HZOJ 20190727 T2 单(树上dp+乱搞?+乱推式子?+dfs?)

    考试T2,考试时想到了40pts解法,即对于求b数组,随便瞎搞一下就oxxk,求a的话,很明显的高斯消元,但考试时不会打+没开double挂成10pts(我真sb),感觉考试策略还是不够成熟,而且感觉 ...

随机推荐

  1. springmvc 视图解析器工作不正常

    参考了如下 https://blog.csdn.net/typa01_kk/article/details/45902783 今天搭建了一个新的工程,从头开始搞的,处理完发现,能正常进入control ...

  2. Python发送QQ消息

    一.需求背景 每天早上取一批数据,数据文件经过压缩加密之后用邮箱发送,而解压密码通过QQ发送给运营.使用Python进行取数.文件加密在已经实现的情况下,需要实现通过QQ发送密码的功能.     在进 ...

  3. go语言:类型转换

    类型转换用于将一种类型的变量转换为另一种类型的变量. 有以下场景: package main import "fmt" func main() { var sum int = 17 ...

  4. Codeforces Round #436 (Div. 2) 题解864A 864B 864C 864D 864E 864F

    A. Fair Game time limit per test 1 second memory limit per test 256 megabytes input standard input o ...

  5. JavaScript文件与HTML文件本地连接

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. Django静态文件以及模板文件的配置 jQuery v1.12.4

    1.配置模板的路径 TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os. ...

  7. bzoj 1191 [HNOI2006]超级英雄Hero——二分图匹配

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1191 不就是个最大匹配么. 结果WA得不行. 看TJ后发现题面上说了一旦没回答出一道题就结束 ...

  8. 怎样判断一个exe可执行程序(dll文件)是32位的还是64位的

    看到一个比较简单粗暴的方式,做个记录. 直接用记事本或者notepad++(文本编辑软件都可)打开exe文件(dll文件), 会有很多乱码,接下来只需要在第二段中找到PE两个字母,在其后的不远出会出现 ...

  9. python进程间通信 queue pipe

    python进程间通信 1 python提供了多种进程通信的方式,主要Queue和Pipe这两种方式,Queue用于多个进程间实现通信,Pipe是两个进程的通信 1.1 Queue有两个方法: Put ...

  10. C++学习笔记----3.2 C++引用在本质上是什么,它和指针到底有什么区别

    从概念上讲.指针从本质上讲就是存放变量地址的一个变量,在逻辑上是独立的,它可以被改变,包括其所指向的地址的改变和其指向的地址中所存放的数据的改变. 而引用是一个别名,它在逻辑上不是独立的,它的存在具有 ...