题目背景
没有背景
我写不出来了qwq
题目描述
Chino给定了nn个数a_1...a_na1...an,给定常数s,m,她会轮流对这nn个数做k组操作,每组操作包含以下几步:
1.swap(as,am)(交换a_s,a_m)
2.2将n个数都向前平移一位(第11个移动到第n个位置上)
Chino想知道,k组操作后,这nn个数分别是多少?
Orz yky,dyh,wjk,jjy,cxr,gsy,cpy,zcy,tyz,yy,hz,zhr,yg
输入格式
第一行,四个数,n,s,m,k
接下来一行n个数,分别代表a_1,a_2...a_na1,a2...an
输出格式
输出一行,n个数,分别代表a_1,a_2...a_na1,a2...an
输入输出样例
输入 #1
4 1 2 3 1 2 3 4
输出 #1
1 2 3 4
说明/提示
所有数字均在long long以内
思路:
矩阵加速递推,构造两个矩阵,一个存交换操作,一个存位移操作。
假如交换1和2:
0 1 0 0
1 0 0 0
0 0 0 1
0 0 0 1
位移操作,所有往前移一位,
0 1 0 0
0 0 1 0
0 0 0 1
1 0 0 0
矩阵快速幂求解K次方,即操作次数:
jz ksm(jz a,int b) { jz anss; memset(anss.c,0,sizeof(anss.c)); for(int i=1;i<=n;i++) anss.c[i][i]=1; for(;b;b>>=1,a=a*a) { if(b&1)anss=a*anss; // a=a*a;当时出错了,因为前面已经计算 } return anss; }
重载乘号:
struct jz{ int c[100][100]; }f,base,l1,l2; int n,m,s,k; jz operator * (const jz &a,const jz &b) { jz lin; for(int i=1;i<=80;i++) for(int j=1;j<=80;j++) { lin.c[i][j]=0; for(int k=1;k<=80;k++) { lin.c[i][j]+=(a.c[k][j] * b.c[i][k]); } } return lin; }
代码:
#include<cstdio> #include<cstdlib> #include<iostream> #include<cmath> #include<cstring> #define int long long using namespace std; struct jz{ int c[100][100]; }f,base,l1,l2; int n,m,s,k; jz operator * (const jz &a,const jz &b) { jz lin; for(int i=1;i<=80;i++) for(int j=1;j<=80;j++) { lin.c[i][j]=0; for(int k=1;k<=80;k++) { lin.c[i][j]+=(a.c[k][j] * b.c[i][k]); } } return lin; } void dy(jz x)//调试用的,可以忽略 { for(int i=1;i<=n;++i) { for(int j=1;j<=n;++j) cout<<x.c[i][j]<<" "; cout<<endl; } } jz ksm(jz a,int b) { jz anss; memset(anss.c,0,sizeof(anss.c)); for(int i=1;i<=n;i++) anss.c[i][i]=1; for(;b;b>>=1,a=a*a) { if(b&1)anss=a*anss; // a=a*a; } return anss; } signed main() { scanf("%lld%lld%lld%lld",&n,&s,&m,&k); for(int i=1;i<=n;i++) scanf("%lld",&f.c[i][1]); for(int i=1;i<=n;i++) if(i!=s&&i!=m)l1.c[i][i]=1; l1.c[s][m]=l1.c[m][s]=1; for(int i=1;i<=n-1;i++)l2.c[i][i+1]=1; l2.c[n][1]=1; base=l1*l2; base=ksm(base,k); f=f*base; for(int i=1;i<=n;i++)printf("%lld ",f.c[i][1]); cout<<endl; dy(l1); cout<<endl; dy(l2); return 0; }
感谢wlj_dy 的帮助