您的位置:首页 > 其它

UvaLive 3704 Cellular Automaton (矩阵快速幂)

2017-03-26 11:09 330 查看
题目原文:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1705

A cellular automaton is a collection of cells on a grid of specified shape that evolves through a number of discrete time steps according to a set of rules that describe the
new state of a cell based on the states of neighboring cells. The order of the cellular automaton is the number of cells it contains. Cells of the automaton of order n are numbered from 1 to n. The order of the cell is the number of different values it may
contain. Usually, values of a cell of order m are considered to be integer numbers from 0 to m−1. One of the most fundamental properties of a cellular automaton is the type of grid on which it is computed. In this problem we examine the special kind of cellular
automaton — circular cellular automaton of order n with cells of order m. We will denote such kind of cellular automaton as n,m− automaton. A distance between cells i and j in n,m-automaton is defined as min(|i − j|,n −|i − j|). A denvironment of a cell is
the set of cells at a distance not greater than d. On each d-step values of all cells are simultaneously replaced by new values. The new value of cell i after d-step is computed as a sum of values of cells belonging to the d-enviroment of the cell i modulo
m. The following picture shows 1-step of the 5,3-automaton.

The problem is to calculate the state of the n,m-automaton after k d-steps.

Input

The input file contains several test cases, each of them consists of two lines, as described below. The first line of the input contains four integer numbers n, m, d, and k (1 ≤ n ≤ 500, 1 ≤ m ≤ 1000000, 0 ≤ d < n 2 , 1 ≤ k ≤ 10000000). The second line contains
n integer numbers from 0 to m−1 — initial values of the automaton’s cells.

Output

For each test case, write to the output, on a line by itself, the values of the n,m-automaton’s cells after k d-steps.

解题思路:

最简单的思路是构造 n*n 矩阵来实现每次求和的过程。但是矩阵乘积的复杂度是 O(n^3) 的。再多一个log的复杂度可能就难以承受了。所以要想一想有没有办法能够降低复杂度。由题意可知,构造出来的系数矩阵一定是一个循环矩阵,每一行都是由上一行向右平移一个单位形成的。这是线性代数里面的循环矩阵,有关循环矩阵有一个重要的性质就是循环矩阵的乘积仍然为循环矩阵。想了解证明的朋友可以看这篇文章https://wenku.baidu.com/view/11e6312bcfc789eb172dc8ed.html 简单来说就是可以证明每一条斜线上面的元素都满足下标加和模
n 同余。

有了这个重要结论以后,我们就可以优化我们的矩阵快速幂算法,即每次只计算一行,通过计算算出每一个位置的元素在第一行中对应的坐标。就可以求解了。

AC代码:

/*
@Author: wchhlbt
@Date:   2017/3/18
*/
#include <bits/stdc++.h>

#define Fori(x) for(int i=0;i<x;i++)
#define Forj(x) for(int j=0;j<x;j++)
#define maxn 600
#define inf 0x3f3f3f3f
#define ONES(x) __builtin_popcount(x)
using namespace std;

typedef long long ll ;
const double eps =1e-8;
const int mod = 1000000007;
const double PI = acos(-1.0);
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};

ll MAXN,MOD;
//注意两个量 MAXN 、 MOD
typedef struct
{
ll mat[maxn];
} Matrix;

///求得的矩阵
Matrix P;
///单位矩阵
Matrix I;
void init()
{
I.mat[0] = 1;
}
///矩阵乘法
Matrix Mul_Matrix(Matrix a, Matrix b)
{
Matrix c;
for(int i=0; i<MAXN; i++)
{
c.mat[i] = 0;
for(int j=0; j<MAXN; j++)
{
c.mat[i] += (a.mat[j] * b.mat[(i-j+MAXN)%MAXN]) % MOD;
c.mat[i] %= MOD;
}
}
return c;
}
///矩阵的快速幂
Matrix quick_Mod_Matrix(ll m)
{
Matrix ans = I, b = P;
while(m)
{
if(m & 1)
ans = Mul_Matrix(ans, b);
m>>=1;
b = Mul_Matrix(b, b);
}
return ans;
}

ll f[maxn];

int main()
{
//freopen("test.txt","r",stdin);
ll n,m,k,d;
while(cin>>n>>m>>d>>k){
MAXN = n; MOD = m;
memset(P.mat, 0, sizeof(P.mat));
init();
for(int i = 0; i<n; i++)
cin>>f[i];
P.mat[0] = 1;
for(int i = 1; i<=d; i++){
P.mat[i] = 1;
P.mat[n-i] = 1;
}
Matrix ans = quick_Mod_Matrix(k);
for(int i = 0; i<n; i++){
ll res = 0;
for(int j = 0; j<n; j++){
res = (res+f[j]*ans.mat[(j-i+n)%n])%MOD;
}
if(i!=0)    cout << " ";
cout << res;
}
cout << endl;
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: