网络赛使人自闭,目前为止还缺了好多知识点我哭了。
-
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;
} 
京公网安备 11010502036488号