题意:
某铲屎官让一群喵星人n只(100)锻炼身体。
有以下操作:
g i:第 i 只喵星人拿到一颗花生。
e i:第 i 只喵星人吃掉它所有的花生。
s i j:第 i 只喵星人和第 j 只喵星人交换他们的花生。
现在问,操作m(1,000,000,000)次以后,每只喵星人手上的花生状态是啥。
m也没有大到丧心病狂的地步嘛。
解析:
矩阵的建立过程参照:
然后值得注意的是,稀疏矩阵的乘法可以剪枝。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1
using namespace std;
const int inf = 0x3f3f3f3f;
typedef vector<LL> vec;
typedef vector<vec> mat;
LL n, m, k;
mat mul(mat &A, mat &B)
{
mat C(A.size(), vec(B[0].size()));
for (int i = 0; i < A.size(); i++)
{
for (int k = 0; k < B.size(); k++)
{
if (A[i][k])///由于是稀疏矩阵,所以很多0存在,加这个剪枝就过了。
for (int j = 0; j < B[0].size(); j++)
{
// C[i][j] = (C[i][j] + A[i][k] * B[k][j]) % mod;
C[i][j] = (C[i][j] + A[i][k] * B[k][j]);
}
}
}
return C;
}
mat pow(mat A, LL n)
{
mat B(A.size(), vec(A.size()));
for (int i = 0; i < A.size(); i++)
{
B[i][i] = 1;
}
while (0 < n)
{
if (n & 1)
B = mul(B, A);
A = mul(A, A);
n >>= 1;
}
return B;
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
while (~scanf("%lld%lld%lld", &n, &m, &k))
{
if (!n && !m && !k)
break;
mat A(n + 1, vec(n + 1));
for (int i = 0; i < n + 1; i++)
A[i][i] = 1;
for (int i = 0; i < k; i++)
{
char op[2];
scanf("%s", op);
if (op[0] == 'g')
{
int x;
scanf("%d", &x);
A[n][x - 1]++;
}
else if (op[0] == 'e')
{
int x;
scanf("%d", &x);
for (int j = 0; j <= n; j++)
{
A[j][x - 1] = 0;
}
}
else
{
int u, v;
scanf("%d%d", &u, &v);
for (int j = 0; j <= n; j++)
{
swap(A[j][u - 1], A[j][v - 1]);
}
}
}
mat B(n + 1, vec(n + 1));
B[0][n] = 1;
mat ans = pow(A, m);
ans = mul(B, ans);
for (int i = 0; i < n; i++)
{
printf("%lld%c", ans[0][i], i == n - 1 ? '\n' : ' ');
}
}
return 0;
}