Time Limit: 18000MS | 64bit IO Format: %lld & %llu |
題意:
對一個圈裏的n個數字進行操作,每次操作都將數字i與其相鄰距離d以內的數字加起來對m取餘。共進行k次操作,問你k次操作後各數爲多少。
分析:
感覺上是矩陣快速冪,沒想到n這麼大,書上寫的循環矩陣悟了半天也悟不到,最後貌似由於矩陣開太大,傳參時爆內存。最後發現了循環矩陣的做法是隻求第一行,但是處理矩陣相乘時需要注意,因爲循環矩陣可由第一行求出整個矩陣,因此順序需要搞清楚。相乘搞定了其他都是基本的快速冪過程。
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
#define INF 0x3f3f3f3f
const long long N=505;
const long long mod=1e9;
const double PI=acos(-1.0);
typedef long long ll;
typedef struct {
ll mat[N];
}Mat;
int n,d,m,k;
Mat multi(Mat a,Mat b) {
Mat c;
memset(c.mat, 0, sizeof(c.mat));
for (int i=1; i<=n; i++) {
for (int j=1; j<=n; j++) {
c.mat[i]+=a.mat[j]*b.mat[(i-j+n)%n+1];
c.mat[i]%=m;
}
}
return c;
}
Mat qui(Mat a,int b) {
Mat c;
memset(c.mat, 0, sizeof(c.mat));
c.mat[1]=1;
while (b) {
if (b&1) {
c=multi(c, a);
}
a=multi(a, a);
b>>=1;
}
return c;
}
int main() {
int f[N];
Mat A;
while (cin>>n>>m>>d>>k) {
memset(f, 0, sizeof(f));
for (int i=1; i<=n; i++) {
scanf("%d",&f[i]);
}
memset(A.mat, 0, sizeof(A.mat));
for (int i=1; i<=1; i++) {
A.mat[i]=1;
for (int j=1; j<=d; j++) {
A.mat[(i-1+j)%n+1]=1;
A.mat[(i-1-j+n)%n+1]=1;
}
}
A=qui(A, k);
ll res[N];
memset(res, 0, sizeof(res));
for (int i=1; i<=n; i++) {
for (int j=1; j<=n; j++) {
// cout<<A.mat[(j+i-2)%n+1]*f[j]<<endl;
res[i]+=A.mat[(i-j+n)%n+1]*f[j];
res[i]%=m;
}
}
for (int i=1; i<n; i++) {
printf("%lld ",res[i]);
}
cout<<res[n]<<endl;
}
return 0;
}