代码编织梦想

传送门:ATcoder

题目描述:

Given integers A, X, and M,find ∑ i = 0 X − 1 A i \sum\limits_{i=0}^{X-1}Ai i=0X1Ai,modulo M

输入:
1000000000 1000000000000 998244353
输出:
919667211

首先X的范围达到了 1 e 12 1e12 1e12,所以 O ( X ) O(X) O(X)的算法肯定是过不了的.

然后当时我赛时就想起来之前有一次我做过一道自幂的题目,然后对与一个数不断自幂取模来说,必存在一个循环节.这个我在上述链接中已经有详细证明+解释,此处就不在赘述了.然后我就基于循环节的想法去打这道题.复杂度应该是低于 O ( M ) O(M) O(M)的.但是可能是因为取模运算比较慢,所以最后是TLE了.

然后现在讲一下正解.首先假设你没有像我一样sb的去用循环节去做这道题,那么你应该不难发现 A i A^i Ai是一个等比数列,那么原题就是一道等比数列求和的题目,那么你可能十分的激动直接开做, 1 − q X 1 − X \frac{1-q^X}{1-X} 1X1qX,分子只用快速幂可以解决,但是你会发现分母需要使用逆元,但是这个逆元可能是不存在的(可以证明,但是比较麻烦).所以不能直接求.

我们可以换一种想法就是将 ∑ i = 0 X − 1 A i \sum\limits_{i=0}^{X-1}Ai i=0X1Ai看成是一个等比数列的一个通项,也就是设一个 C i = ∑ i = 0 X − 1 A i Ci=\sum\limits_{i=0}^{X-1}Ai Ci=i=0X1Ai,可以显然的发现 C i Ci Ci本身就是一个等比数列,所以我们现在的任务就是求出CX的值即可.我们可以发现 C i = C ( i − 1 ) ∗ A + 1 Ci=C(i-1)*A+1 Ci=C(i1)A+1对于这种数列题,可以使用矩阵来快速解决

考虑有
[ C i ] = [ A 1 ] ∗ [ C i − 1 1 ] \left[ \begin{matrix} Ci \end{matrix} \right]=\left[ \begin{matrix} A&1 \end{matrix} \right]*\left[ \begin{matrix} Ci-1 \\ 1 \end{matrix} \right] [Ci]=[A1][Ci11]

但是为了满足矩阵乘法的正确性(行数相同),我们补充一下两边矩阵

[ C i 1 ] = [ A 1 0 1 ] ∗ [ C i − 1 1 ] \left[ \begin{matrix} Ci \\ 1\end{matrix} \right]=\left[ \begin{matrix} A&1 \\ 0 & 1 \end{matrix} \right]*\left[ \begin{matrix} Ci-1 \\ 1 \end{matrix} \right] [Ci1]=[A011][Ci11]

定义初始矩阵为 C 0 = [ 0 1 ] C0=\left[ \begin{matrix} 0 \\ 1 \end{matrix} \right] C0=[01]
那么 C 1 = [ A 1 0 1 ] ∗ [ 0 1 ] C1=\left[ \begin{matrix} A & 1 \\ 0 & 1 \end{matrix} \right]*\left[ \begin{matrix} 0 \\ 1 \end{matrix} \right] C1=[A011][01]

那么 C X = [ A 1 0 1 ] x ∗ [ 0 1 ] CX=\left[ \begin{matrix} A & 1 \\ 0 & 1 \end{matrix} \right]^{x}*\left[ \begin{matrix} 0 \\ 1 \end{matrix} \right] CX=[A011]x[01]

然后我们直接使用矩阵快速幂来迅速解决这道题即可

下面是具体的代码部分:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
	ll x=0,w=1;char ch=getchar();
	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}
#define int long long
#define maxn 1000000
const double eps=1e-8;
#define	int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int Mod,A,X;
int ans[10][10],x[10][10],c[10][10];
void x_pow() {
	for(int i=0;i<2;i++) {
		for(int j=0;j<2;j++) {
			c[i][j]=x[i][j];
			x[i][j]=0;
		}
	}
	for(int i=0;i<2;i++) {
		for(int j=0;j<2;j++) {
			for(int k=0;k<2;k++) {
				x[i][j]=(x[i][j]+c[i][k]*c[k][j]%Mod)%Mod;
			}		
		}
	}
}
void ans_pow() {
	for(int i=0;i<2;i++) {
		for(int j=0;j<1;j++) {
			c[i][j]=ans[i][j];
			ans[i][j]=0;
		}
	}
	for(int i=0;i<2;i++) {
		for(int j=0;j<1;j++) {
			for(int k=0;k<2;k++) {
				ans[i][j]=(ans[i][j]+x[i][k]*c[k][j]%Mod)%Mod;
			}
		}
	}
}
void juzhen_qpow(int k) {
	while(k) {
		if(k&1) ans_pow();
		k>>=1;
		x_pow();
	}
}
signed main() {
	A=read(),X=read(),Mod=read();
	x[0][0]=A;x[0][1]=1;x[1][0]=0;x[1][1]=1;
	ans[0][0]=0;ans[1][0]=1;
	juzhen_qpow(X);
	cout<<ans[0][0]<<endl;
	return 0;
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yingjiayu12/article/details/129479827

atcoder beginner contest 144 e - gluttony(二分)-爱代码爱编程

题目链接:https://atcoder.jp/contests/abc144/tasks/abc144_e 题意: 有n个人,每个人吃一单位东西的时间为ai,现在有n份食物,每份食物的份量为fi单位。 每个人必须对应一份食

AtCoder题解 —— AtCoder Beginner Contest 186 —— E - Throne —— 欧几里得求逆元-爱代码爱编程

题目相关 题目链接 AtCoder Beginner Contest 186 E 题,https://atcoder.jp/contests/abc186/tasks/abc186_e。 Problem Statement We have N chairs arranged in a circle, one of which is a throne

AtCoder Beginner Contest 194 F - Digits Paradise in Hexadecimal-爱代码爱编程

https://atcoder.jp/contests/abc194/tasks/abc194_f 太菜了又碰到不会的数位DP题了 这题的关键是我们并不用在dp数组中存下当前已经用了哪些数字 只要令dp[pos][cnt][up][lead]=dp[枚举到哪一位了][有几个不同的数字][是否顶着上界][前面是否有非零位了] 只要其中pos,up,l

AtCoder Beginner Contest 201 E - Xor Distances-爱代码爱编程

https://atcoder.jp/contests/abc201/tasks/abc201_e 这应该是个人尽皆知经典傻逼题然而我想了一年 a[u]为根节点到u的异或,dist[i,j]=a[i]^a[j] 然后他要求和,我们发现可以把他们分成二次幂来统计数量求和,然后就没了,我太菜了 #include<bits/stdc++.h>

AtCoder Beginner Contest 134 F - Permutation Oddness-爱代码爱编程

Contents 问题重现数据范围样例InputOutput思路参考 问题重现 原题链接 设 P = ( p

AtCoder Beginner Contest 248 F - Ignore Operations // 贪心 + 大根堆-爱代码爱编程

传送门:F - Keep Connect (atcoder.jp) 题意: 给定长度为N的操作(ti,yi)。 给定初值为0的x,对其进行操作:当t为1时,将x替换为y;当t为2时,将x加上y。 最多可以跳过k步,求最终x的最大值。 思路: 注意到,当t为1时,进行替换操作,那么该位置前面的操作是不会对后面产生任何影响的,也就不会消耗k

atcoder beginner contest 260 e - at least one_~顾安的博客-爱代码爱编程

1.暴力解法         分别枚举长度为1——m(m级别),再枚举好序列的开始位置(m级别)。由于序列的长度和开始位置确定,因此序列确定。再判断是否满足n对数对(n级别)。因此暴力做法至少O(m*m*n)。 2.track          当序列l——r满足n对数对时,序列向左,向右扩张时也一定满足。         根据track,假如

atcoder beginner contest 276---c - previous permutation_小小小why的博客-爱代码爱编程

题目链接 题目大意:给定一个N(<=100),他可以形成1~N根据字典序所有全排列,然后给定其中一个全排列,求出比他上一个的全排列。比如N=3,所有排列方式如下图(按照字典序),给定其中一个,求出上一个,题目保证给定的不是第一个 1 2 3 1 3 2 2 1 3 2 3 1 3 1 2 3 2 1 胡思乱想:因为N<=10

atcoder beginner contest 282 a-e-爱代码爱编程

比赛名称:HHKB Programming Contest 2022 Winter(AtCoder Beginner Contest 282) 比赛链接:AtCoder Beginner Contest 282  A - Generalized ABC 给定字符串长度k,输出该字符串,该字符串由A,B,C...拼接得到 。 #inclu

atcoder beginner contest 154e - almost everywhere zero-爱代码爱编程

比赛名称:AtCoder Beginner Contest 154 原题链接:E - Almost Everywhere Zero 题意:计算1-N之间有多少整数的 非零位数量恰好为K  思路:经典数位DP 本题解法采用 组合数递推的形式完成数位dp #include <bits/stdc++.h> using names

atcoder beginner contest 290 d - marking (结合官方题解的证明和解析) 思维 + 裴蜀定理-爱代码爱编程

D - Marking 题目链接:D - Marking 官方题解链接:Editorial 题意 给定 N

atcoder beginner contest 247 e -爱代码爱编程

原题链接:E - Max Min (atcoder.jp) 题意: 给定一个数组,求满足最大值为X且最小值为Y的区间个数。 思路: 因为必须要包含端点,直接求是不容易的。因此考虑去求不一定包含端点的区间数量,再做容斥。 代码参考: //Jakon:容斥原理 #include <bits/stdc++.h> #define

atcoder beginner contest 248 e -爱代码爱编程

原题链接:E - K-colinear Line (atcoder.jp) 题意: 给出直角坐标系上N个点(N <= 300),求经过这些点中至少K个点的直线数量,若有无穷多条,则输出"Infinity"。 思路: 两点确定一条直线: 当K=1时,答案自然是无穷多条。 当K >= 2时,我们可以枚举两点,求出其确定的直线,再枚举所

atcoder beginner contest 154 e-爱代码爱编程

Atcoder Beginner Contest 154 E-F 题解 E - Almost Everywhere Zero 解法:简单的数位dp f 为是否在判前导0,g 为是否在卡上界num=0 时刚好有 k

atcoder beginner contest 284 a -爱代码爱编程

题目地址:AtCoder Beginner Contest 284 - AtCoder 一个不知名大学生,江湖人称菜狗 original author: jacky Li Email : 3435673055@qq.com Time of completion:2023.1.8 Last edited: 2023.1.10 目录

atcoder beginner contest 280 a-爱代码爱编程

A - Pawn on a Grid 题意:就是让你求出这个n行n列中‘#’的个数 思路:直接枚举就行了。 代码: /* by:lwq132lwq */ #include<bits/stdc++.h> using namespace std; #define IO ios::sync_with_stdio(false);cin