博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
病毒分裂 NOIP模拟 矩阵快速幂 分治数列求和
阅读量:6956 次
发布时间:2019-06-27

本文共 2415 字,大约阅读时间需要 8 分钟。

题面在最下方。

吐个槽,矩阵我没写long long挂了40分 (事实上正常写法不用long long,但。。我。。不正常)

首先推一下简单的结果找找感觉,就可以得到一个结论:第n个阶段的病毒数An=K^(n-1)

等比数列求和会吗?Sn=S1+S2+...+Sn=1+K+K2+...+Kn-1,由于题目说的是第n阶段前有多少个病毒分裂,那么答案就是Sn-1

但是我们发现,这个坑逼玩意儿不太好求。

为啥?如果你用求和公式的话,要写个高精度,除啊模啊,想想都头大!如果你不用高精度 ,偏要O(n)枚举求和的话,本题nmax=10^18,那就非常有意思了。

怎么搞?都想到这里了,难道还要放弃?

天无绝人之路,本题解法一就出来了:这玩意可以分治解决

思路:设问题求的是1 + K + K2 + K3 + ⋯ + KM, 对 此式子分治解决,先求得1 + K + ⋯ + KM/2-1 , 然后KM/2 + ⋯ + KM等于前式乘以KM/2 得到,将两式合并即可,而对于前半部分,递归使用以上算法即可,完美地避开 了除法运算。分治共log(N)层,每层只递归计算一边,然后合并调用快速幂,所 以总的复杂度为 O(log2(N))。

1 #include
2 #include
3 using namespace std; 4 #define LL long long 5 LL N, K, P; 6 7 LL ksm(LL x, LL k) { 8 LL res = 1; 9 for (; k>0; x=x*x%P, k>>=1)10 if (k&1) res = res*x%P;11 return res;12 }13 14 LL sum(LL n) {15 if (!n) return 0;16 LL res = sum(n>>1);17 LL res1 = (res + res * ksm(K, n>>1)) % P;18 if (n & 1) return (res1 + ksm(K, n-1)) % P;19 else return res1;20 }21 22 int main()23 {24 freopen("split.in", "r", stdin);25 freopen("split.out", "w", stdout);26 cin >> K >> N >> P;27 K %= P;28 cout << sum(N - 1) << '\n';29 return 0;30 }
分治算法(思路简单,代码简单)

解法二:矩阵快速幂

1 #include
2 #include
3 using namespace std; 4 template
inline void read(T &_a){ 5 int _ch=getchar();_a=0; 6 while(_ch<'0' || _ch>'9')_ch=getchar(); 7 while(_ch>='0' && _ch<='9'){_a=(_a<<1)+(_a<<3)+_ch-'0';_ch=getchar();} 8 } 9 10 long long k,n,p; 11 12 struct matrix13 {14 long long a[2][2];15 matrix() {memset(a,0,sizeof(a));}16 matrix operator * (matrix &x) const {17 matrix res;18 for (register int i=0;i<=1;++i)19 for (register int v=0;v<=1;++v)20 for (register int j=0;j<=1;++j)21 res.a[i][v]+=a[i][j]*x.a[j][v],res.a[i][v]%=p;22 return res;23 }24 };25 26 matrix clac(matrix a,long long b)27 {28 matrix res;29 res.a[0][0]=res.a[1][1]=1;30 while(b)31 {32 if(b&1) res=res*a;33 b>>=1;34 a=a*a;35 }36 return res;37 }38 39 int main()40 {41 read(k); read(n); read(p);42 matrix op;43 op.a[0][0]=k; op.a[1][0]=op.a[1][1]=1;44 op=clac(op,n-2);45 long long ans=op.a[1][0]*k%p;46 ans+=op.a[1][1];47 printf("%lld",ans%p);48 return 0;49 }
View Code

 

转载于:https://www.cnblogs.com/jaywang/p/7704576.html

你可能感兴趣的文章
静态方法里不能使用$this标识调用静态方法
查看>>
建筑结构中的常见CAD技巧
查看>>
RunLoop
查看>>
java多线程 ThreadLocal
查看>>
maven depenencies 不见了
查看>>
关于android实现拖动旋转角度,调整布局参数的思路
查看>>
关于Java集合类迭代删除元素的一些坑
查看>>
注释那些事儿:前端代码质量系列文章(一)
查看>>
向代码致敬,寻找你的第83行
查看>>
【产品功能】配置网卡从此与关机无缘,弹性网卡支持热插拔功能
查看>>
UWP 绑定数据源异常 进入系统断点!global::System.Diagnostics.Debugger.Break();
查看>>
vue附件名字显示打印机的解决方案
查看>>
mysql用户管理 常用sql语句mysql数据库备份恢复
查看>>
比特币耶稣Roger Ver:比特币现金是比特币扩容问题的答案
查看>>
mysql主从常见问题
查看>>
五周第四次课(4月23日)8.6 管道符和作业控制 8.7/8.8 shell变量 8.9 环境变量配置文件...
查看>>
10.32/10.33 rsync通过服务同步 10.34 linux系统日志 10.35 screen工具
查看>>
视频点播开发者实战:视频水印的基本使用
查看>>
用网关zuul时,熔断hytrix里面的坑
查看>>
【死磕 Spring】—– 4 张图带你读懂 Spring IOC 的世界
查看>>