目录
typedef long long ll;
//快速幂返回x^n对mod取模的结果
ll mod_pow(ll x, ll n, ll mod) {
ll res = 1;
while (n > 0) {
if (n & 1)res = res * x % mod;
x = x * x % mod;
n >>= 1;
}
return res;
}
#include<iostream>
using namespace std;
typedef long long ll;
int l, mod = 1e9 + 7;
ll n;
struct Matrix {
ll a[105][105] = { 0 };
}input;
Matrix multiply(Matrix A, Matrix B) { //计算方阵A的平方的函数
int i, j, k;
Matrix ans;
for (int i = 1; i <= l; ++i){
for (int j = 1; j <= l; ++j){
if (A.a[i][j]){
for (int k = 1; k <= l; ++k){
ans.a[i][k] = (ans.a[i][k] + A.a[i][j] * B.a[j][k] % mod) % mod;
}
}
}
}
return ans;
}
Matrix qpow(Matrix A, long long b) { //矩阵快速幂实现函数,完全借鉴快速幂思想;
Matrix ans;
for (int i = 1; i <= l; i++)ans.a[i][i] = 1;
while (b) {
if (b & 1) ans = multiply(ans, A);
A = multiply(A, A);
b >>= 1;
}
return ans;
}
int main() { //主函数,输入矩阵,快速幂处理,输出矩阵
cin >> l >> n;
for (int i = 1; i <= l; i++)
for (int j = 1; j <= l; j++)
cin >> input.a[i][j];
input = qpow(input, n);
for (int i = 1; i <= l; i++) {
for (int j = 1; j <= l; j++)
cout << input.a[i][j]<<" ";
cout << endl;
}
}
矩阵快速幂实战:
CodeForces 185A Plant 
POJ 3233 Matrix Power Series
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
int n, k, mod ;
struct Matrix { //定义矩阵结构体
int r, c;
ll a[105][105] ;
}A,K,Init,res;
Matrix multiply(Matrix A, Matrix B) { //矩阵A,B相乘模板,适用于所有矩阵;
int i, j, k;
Matrix ans;
memset(ans.a,0,sizeof(ans.a));
ans.r = A.r; ans.c = B.c;
for (int i = 1; i <= A.r; ++i) {
for (int j = 1; j <= A.c; ++j) {
if (A.a[i][j]) {
for (int k = 1; k <= B.c; ++k) {
ans.a[i][k] = (ans.a[i][k] + A.a[i][j] * B.a[j][k] % mod) % mod;
}
}
}
}
return ans;
}
Matrix qpow(Matrix A, long long b) { //矩阵快速幂函数
Matrix ans;
ans.r = ans.c = 2 * n;
memset(ans.a,0,sizeof(ans.a));
for (int i = 1; i <= A.c; i++)ans.a[i][i] = 1;
while (b) {
if (b & 1) ans = multiply(ans, A);
A = multiply(A, A);
b >>= 1;
}
return ans;
}
int main() { //输入待处理矩阵 -> 构造系数矩阵,初始矩阵 ->系数矩阵快速幂 -> K*Init得到答案
cin >> n >> k >> mod;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
cin >> A.a[i][j];
A.r = A.c = n;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (i == j)K.a[i][j] = 1;
else K.a[i][j] = 0;
for (int i = n + 1; i <= 2 * n; i++)
for (int j = 1; j <= n; j++)
K.a[i][j] = 0;
for (int i = 1; i <= 2 * n; i++)
for (int j = n + 1; j <= 2 * n; j++)
K.a[i][j] = A.a[(i-1) % n+1][j - n];
K.r = K.c = 2 * n;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
Init.a[i][j]=0;
for (int i = n+1; i <= 2*n; i++)
for (int j = 1; j <= n; j++)
if (i-n == j)Init.a[i][j] = 1;
else Init.a[i][j] = 0;
Init.r=2*n;Init.c=n;
K=qpow(K,k);
res = multiply(K, Init);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++)
cout << res.a[i][j] << " ";
cout << endl;
}
}
算法Tips: 关于快速幂:数在计算机内以二进制保存,这就表示对于任何自然数 n,一定能表示成 n = +
+ ... +
的形式,其中
。例:22 = 2 + 4 + 16 ;于是有
=
*
*
。这样,枚举
,并通过对幂数位运算判断是否需要相乘,这样就能将原本时间复杂度为 O(n)的乘幂算法降为 O(logn)。
#include<iostream>
#include<algorithm>
using namespace std;
int sum, nsum,a[100005]; //sum记录目标总和,nsum记录当前总和,a[]记录数组
int n,index, len; //len记录最短长度
void count() {
len = n +1;
index = 0;
for (int i = 0; i < n; i++){ //从下标为i的数开始尺取;
while (index < n && nsum < sum){
nsum += a[index];
index++;
}
if (nsum >= sum) len = min(len, index - i ); //找满足条件的最小长度
nsum -= a[i]; //去掉开头的数,下一次循环将从当前所取数段的第二个数开始取
}
}
int main() { //输入 -> 尺取 -> 输出答案
int k;
cin >> k;
while (k--) {
nsum = 0;
cin >> n >> sum;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
count();
cout << (len == n +1 ? 0 : len) << endl;
}
}
#include<iostream>
#include<vector>
using namespace std;
typedef pair<int, int>p;
typedef long long ll;
ll sz, sum, sq,n;
ll be = 1, en = 1;
vector<p>ans;
p p1;
int main() {
cin >> n;
while (1)
{
while (sum < n) { //从be的位置尺取一段平方和大于等于n的数列
sq = en * en;
sum += sq;
en++;
}
if (sq > n) break; //最大的平方数比目标数大,不可能再有答案
if (sum == n) //找到一种可能解,加入答案数列
{
p1.first = be; p1.second = en;
ans.push_back(p1);
}
sum -= be * be; //尺取开头的位置+1;
be++;
}
sz = ans.size(); //按照题目要求格式输出答案
cout << sz << endl;
for (int i = 0; i < sz; ++i) {
int l = ans[i].first;
int r = ans[i].second;
cout << r - l << " ";
for (int j = l; j < r; ++j) {
cout << j << " ";
}
cout << endl;
}
}
算法Tips:尺取法(双指针)的用途是比较广泛的。有的时候在一个O(n^2)的算法里面能够优化许多。简要做法:维护两个表示下标的指针left,right,代表当前区间的左右端点。让右端点不断右移,直到出现答案,然后左端点右移一次,重复上述操作直到右端点到头。显然,这样做必须保证答案在区间上的单调性。