网络赛使人自闭,目前为止还缺了好多知识点我哭了。
-
Matrix Power Series
VJ链接:https://vjudge.net/problem/POJ-3233
难点在于推出Sk,Ak的递推式,将答案转换为常数矩阵的幂次方形式,还有可以在矩阵中补零转换为方阵。
注释都在代码里拉,还有取余的时候注意不要出现负数的情况,可以(x+mod)%mod.(此题不存在这个坑)
#include<bits/stdc++.h> using namespace std; #define endll printf("\n") #define s1(a) scanf("%d",&a) #define lowbit(x) ((x)&(-x)) #define sl1(a) scanf("%lld",&a) #define s2(a,b) scanf("%d%d",&a,&b) #define mem(a,b) memset(a,b,sizeof(a)) #define sl2(a,b) scanf("%lld%lld",&a,&b) #define s3(a,b,c) scanf("%d%d%d",&a,&b,&c) int n,k,m; //E为n*n的单位矩阵 //(E,A)*(Sk-1,0)=(Sk,0); //(0,A)*(Ak-1,0)=(Ak,0); // struct IN { int a[111][111]; IN operator *(IN &b) { IN c;mem(c.a,0); for(int i=0;i<n;i++) for(int j=0;j<n;j++) for(int k=0;k<n;k++) c.a[i][j]=(c.a[i][j]+a[i][k]*b.a[k][j])%m; return c; } }st,ans,tmp; void mtpow() { while(k) { if(k&1) ans=ans*st; st=st*st; k>>=1; } //求出st的k-1次幂,与 //(A,0) //(A,0) //相乘 ans=ans*tmp; n>>=1; for(int i=0;i<n;i++) { for(int j=0;j<n;j++) printf("%d ",ans.a[i][j]); endll; } } int main() { s3(n,k,m); //构造初始矩阵 mem(st.a,0); //左上角 for(int i=0;i<n;i++) st.a[i][i]=1; //右上和右下 for(int i=0;i<n;i++) for(int j=n;j<n*2;j++) { s1(st.a[i][j]); st.a[i+n][j]=st.a[i][j]; tmp.a[i][j-n]=tmp.a[i+n][j-n]=st.a[i][j]; } //构造求该矩阵n次幂的矩阵 mem(ans.a,0); n<<=1;k--; for(int i=0;i<n;i++) ans.a[i][i]=1; mtpow(); return 0; }
-
Kiki & Little Kiki 2(思维)
VJ链接:https://vjudge.net/problem/HDU-2276
题意:每秒钟灯的状态由本身和他左边的灯决定,左边的灯开着则将此灯反转,问m秒之后每个灯的状态
思路:难点在于把递推公式找出来,构造出常数矩阵。
先考虑第一个灯:影响它新状态的只有它左右的灯和它自己的状态,仔细想一下,1*n的转移中只有这两位置有用,那么
最后:
最后要注意的一点就是,计算f[n]的时候,把st初始化为常数矩阵1次幂形式,
之后可以把ans初始化为单位矩阵,算出常数矩阵的k次幂之后ans再与初始状态矩阵相乘。
也可以一开始就把ans初始化为初始状态矩阵(E*A=A嘛,先乘后乘都一样的),然后与st做k次幂乘。
要注意构造矩阵的行列关系,因为计算矩阵乘的时候为ans*st;
为保证状态矩阵中的状态与常数相乘,初始化时状态存在第0行而不是0列。
#include<bits/stdc++.h> using namespace std; #define endll printf("\n") #define s1(a) scanf("%d",&a) #define mem(a,b) memset(a,b,sizeof(a)) int n,k;//灯的个数以及矩阵大小 char s[111]; struct IN { int a[111][111]; IN operator *(IN &b) { IN c;mem(c.a,0); for(int i=0;i<n;i++) for(int j=0;j<n;j++) for(int k=0;k<n;k++) c.a[i][j]=(c.a[i][j]+(a[i][k]&b.a[k][j]))%2; return c; } }st,ans; void mtpow() { while(k) { if(k&1) ans=ans*st;//注意这里的顺序,按行构造还是按列构造,因矩阵乘法不满***换律 st=st*st; k>>=1; } for(int i=0;i<n;i++) printf("%d",ans.a[0][i]); endll; } int main() { while(~s1(k)) { scanf("%s",s);n=strlen(s); mem(st.a,0);mem(ans.a,0); for(int i=0;i<n;i++) { st.a[i][i]=st.a[(i-1+n)%n][i]=1;//错误示范a[((i-1+n)%n][i]... ans.a[0][i]=s[i]-'0';//错误示范ans.a[i][0]=s[i]-'0'; } mtpow(); } return 0; }
-
233 Matrix(待更)
VJ链接:https://vjudge.net/problem/HDU-5015
题意:给个矩阵,第0行是0,233,2333....,第0列是0,a1,a2...(输入n个数字)。求构造出的矩阵an,m。
思路:写过两个矩阵的题了所以!这个构造矩阵我居然自己写出来了(难道这题很简单。
借一下菊苣的图)
但刚开始直接拿ans表示常数矩阵,st表示第0行,求m幂次不对。。。
这个要先求完常数矩阵的m次幂再与st相乘,,,不知道为啥,,,
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define mod 10000007 #define endll printf("\n") #define s1(a) scanf("%d",&a) #define s2(a,b) scanf("%d %d",&a,&b) #define mem(a,b) memset(a,b,sizeof(a)) int n,m; struct IN { ll a[13][13]; IN operator *(IN &b) { IN c;mem(c.a,0); for(int i=0;i<13;i++) for(int j=0;j<13;j++) for(int k=0;k<13;k++) c.a[i][j]=(c.a[i][j]+(a[i][k]*b.a[k][j]))%mod;//WAAAAAA..不能写+=呀 return c; } }st,ans,tmp; void mtpow() { mem(ans.a,0); for(int i=0;i<13;i++) ans.a[i][i]=1; while(m) { if(m&1) ans=ans*tmp; tmp=tmp*tmp; m>>=1; } ans=ans*st; printf("%lld\n",ans.a[n][0]); } int main() { while(~s2(n,m)) { mem(st.a,0);mem(tmp.a,0); for(int i=1;i<=n;i++) s1(st.a[i][0]); st.a[n+1][0]=3;st.a[0][0]=23; for(int i=0;i<=n;i++) { tmp.a[i][0]=10; tmp.a[i][n+1]=1; for(int j=1;j<=i;j++) tmp.a[i][j]=1; } tmp.a[n+1][n+1]=1; mtpow(); } return 0; }