原题链接:
poj
题意简述
给定一个长度为 n ( < = 100 ) n(<=100) n(<=100)的序列,和一组操作。一组操作由 k ( < = 100 ) k(<=100) k(<=100)个操作组成,有三种,分别是:
- 交换两个数
- 某个单独位置++
- 某个单独位置=0
重复 m ( < = 1 e 9 ) m(<=1e9) m(<=1e9)次。求最后的序列。
思路
我们发现,要重复很多次,但是长度和一组的数量都不大,而且是立方的复杂度。
立方?!想到了什么!
yeah♂,蒟 矩阵。配一张奆佬的图
(原链接,这篇讲的很好)
也就是说,我们构造一个转移矩阵
T
T
T,一开始是一个单位矩阵(对角线是
1
1
1的矩阵)
对于:
- 交换 ( a , b ) (a,b) (a,b):交换 T T T的第 a , b a,b a,b两行( O ( n ) O(n) O(n))
- 点 a a a++: T T T第 a a a行第 n + 1 n+1 n+1个位置++
- 点 a a a清零:清零 T T T第 a a a行。
然后就用
T
T
T左乘初始矩阵矩阵
[
0
0
.
.
.
0
(
n
个
0
)
1
]
\begin{bmatrix} 0\\ 0\\ ...\\ 0(n个0)\\ 1 \end{bmatrix}
⎣⎢⎢⎢⎢⎡00...0(n个0)1⎦⎥⎥⎥⎥⎤
然后输出乘完的结果即珂。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
namespace Flandle_Scarlet
{
#define int long long
class Matrix//square matrix
{
#define N 110//changeable
private:
int a[N][N];
public:
//variable list
int n;//size
//initialization
Matrix()
{
memset(a,0,sizeof(a));
n=0;
}
Matrix(int _n)
{
memset(a,0,sizeof(a));
n=_n;
}
Matrix(int _n,int _x)
{
n=_n;
for(int i=0;i<N;++i)
{
for(int j=0;j<N;++j)
{
a[i][j]=_x;
}
}
}
//get value
int* operator[](int i)
{
return *(a+i);
}
//set value
void Set(int x)
{
for(int i=0;i<N;++i)
{
for(int j=0;j<N;++j)
{
a[i][j]=x;
}
}
}
void Identity()
{
memset(a,0,sizeof(a));
for(int i=0;i<N;++i)
{
a[i][i]=1;
}
}
#undef N //110
};
Matrix operator*(Matrix x,Matrix y)
{
Matrix ans(x.n,0);
int n=ans.n;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=n;++j)
{
if (x[i][j])
{
for(int k=1;k<=n;++k)
{
ans[i][k]+=x[i][j]*y[j][k];
}
}
}
}
return ans;
}
Matrix operator^(Matrix x,int p)
{
Matrix ans(x.n,1);
ans.Identity();
while(p)
{
if (p&1) ans=ans*x;
x=x*x,p>>=1;
}
return ans;
}
int n,m,k;
Matrix Trans(105,0);
void Lineswap(int a,int b)
{
for(int i=1;i<=n+1;++i)
{
swap(Trans[a][i],Trans[b][i]);
}
}
void Lineadd(int a)
{
++Trans[a][n+1];
}
void Linecls(int a)
{
for(int i=1;i<=n+1;++i)
{
Trans[a][i]=0;
}
}
void Soviet()
{
Trans.Set(0);
Trans.Identity();
for(int i=1;i<=k;++i)
{
char c[4];scanf("%s",c);
if (c[0]=='g')
{
int a;scanf("%lld",&a);
Lineadd(a);
}
if (c[0]=='s')
{
int a,b;scanf("%lld%lld",&a,&b);
Lineswap(a,b);
}
if (c[0]=='e')
{
int a;scanf("%lld",&a);
Linecls(a);
}
}
Matrix Init(n+1,0);
Init[n+1][1]=1;
Init=(Trans^m)*Init;
for(int i=1;i<=n;++i)
{
printf("%lld ",Init[i][1]);
}putchar('\n');
}
void IsMyWife()
{
if (0)
{
freopen("","r",stdin);
freopen("","w",stdout);
}
while(scanf("%lld%lld%lld",&n,&m,&k) and n+m+k)
{
Soviet();
}
}
#undef int //long long
};
int main()
{
Flandle_Scarlet::IsMyWife();
return 0;
}