B - 233 Matrix
我们一列一列的看,可以发现每一列可以由前一列推出,而且题目给的行数特别少,也算是给了一个提示:以列作为递推的对象。
#include
using namespace std;
const int maxn=15;
const int mod=10000007;
typedef long long ll;
struct M
{
int n,m;
ll a[maxn][maxn];
M(int _n=0)
{
n = m = _n;
memset(a, 0, sizeof(a));
}
M(int _n, int _m)
{
n = _n, m = _m;
memset(a, 0, sizeof(a));
}
void mem(int _n = 0)
{
n = m = _n, memset(a, 0, sizeof(a));
}
void mem(int _n, int _m)
{
n = _n, m = _m;
memset(a, 0, sizeof(a));
}
friend M operator*(M a, M b)
{
M c(a.n,b.m);
for (int k = 1; k <= a.m; k++)
for (int i = 1; i <= a.n; i++)
for (int j = 1; j <= b.m; j++)
(c.a[i][j] += (a.a[i][k] * b.a[k][j])%mod)%=mod;
return c;
}
void make_I(int _n)
{
n = m = _n;
memset(a, 0, sizeof(a));
for (int i = 1; i <= n; i++)a[i][i] = 1;
}
void out()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
cout<' ';
cout<int num,M a)
{
M res;
res.make_I(a.n);
while(num)
{
if(num%2)
res=res*a;
num/=2;
a=a*a;
}
return res;
}
int a[maxn];
int main()
{
int n,m;
while(~scanf("%d %d",&n,&m))
{
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
a[0]=23;
a[n+1]=3;
int times=m;
M it(n+2);
for(int i=1;i<=n+2;i++)
for(int j=1;j<=n+2;j++)
{
if(j==1)
{
if(i!=n+2)
it.a[i][j]=10;
}
else if(j==n+2)
it.a[i][j]=1;
else
{
if(i>=j&&i2)
it.a[i][j]=1;
}
}
//it.out();
M res=quick_mul(times,it);
//res.out();
ll ans=0;
for(int i=1;i<=n+2;i++)
{
(ans+=(res.a[n+1][i]*a[i-1])%mod)%=mod;
}
printf("%lld\n",ans);
}
return 0;
}
D - Krypton Number System
设dp[i][j] 为已经获得的分数为i,最后的数字为j。那么dp[i][j]=dp[i][j]+dp[i-(j-k)*(j-k)][k].
容易看出,这个式子的复杂度为score*base*base.所以我们需要将其进行优化。
优化的方式肯定是矩阵啦,毕竟在这个专题。我们可以发现一个score必定最少是从score-(base-1) * (base-1)得来的。所以我们可以以这个范围的分数作为递推的对象,而j是从0到base-1,那么矩阵的大小为 (base-1) * (base-1)*base.
具体的矩阵如下所示。
#include
using namespace std;
typedef unsigned int uint;
const int maxn=160;
struct M
{
int n, m;
uint a[maxn][maxn];
M(int _n = 0) { n = m = _n;memset(a, 0, sizeof(a)); }
M(int _n, int _m) { n = _n, m = _m;memset(a, 0, sizeof(a)); }
void mem(int _n = 0) { n = m = _n, memset(a, 0, sizeof(a)); }
void mem(int _n, int _m) { n = _n, m = _m;memset(a, 0, sizeof(a)); }
friend M operator*(M a, M b)
{
M c(a.n,b.m);
for (int k = 1;k <= a.m;k++)
for (int i = 1;i <= a.n;i++)
for (int j = 1;j <= b.m;j++)
c.a[i][j] += a.a[i][k] * b.a[k][j];
return c;
}
void make_I(int _n)
{
n = m = _n;
memset(a, 0, sizeof(a));
for (int i = 1;i <= n;i++)a[i][i] = 1;
}
void out()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
cout<' ';
cout<int num,M a)
{
M res;
res.make_I(a.n);
M tmp=a;
while(num)
{
if(num%2)res=res*tmp;
num/=2;
tmp=tmp*tmp;
}
return res;
}
int base,score;
uint dp[30][10];
void pre_init()
{
memset(dp,0,sizeof(dp));
for(int i=1;i<=base-1;i++)
dp[0][i]=1;
for(int i=1;i<=(base-1)*(base-1)-1;i++)
for(int j=0;j<=base-1;j++)
{
for(int k=0;k<=base-1;k++)
{
if((j-k)*(j-k)>i||j==k)continue;
dp[i][j]+=dp[i-(j-k)*(j-k)][k];
}
}
}
int main()
{
int T;
scanf("%d",&T);
int cas=1;
while(T--)
{
scanf("%d %d",&base,&score);
int len=(base-1)*(base-1)*base;
M a(len);
int nowr=1,nowc=base+1;
while(nowc<=len)
{
a.a[nowr][nowc]=1;
nowr++,nowc++;
}
int val=(base-1)*(base-1);
for(int i=0;i<base;i++,nowr++)
{
for(int j=0;j<base;j++)if(i!=j)
{
int bef=val-(i-j)*(i-j);
int itc=bef*base+j+1;
a.a[nowr][itc]=1;
}
}
//a.out();
pre_init();
printf("Case %d: ",cas++);
if(score<=(base-1)*(base-1)-1)
{
uint ans=0;
for(int i=0;i<=base-1;i++)
ans=ans+dp[score][i];
cout<else
{
int times=score-(base-1)*(base-1)+1;
M res=quick_mul(times,a);
uint ans=0;
for(int i=0;i<=base-1;i++)
{
for(int j=1;j<=len;j++)
{
int r=(j-1)/base;
int c=(j-1)%base;
ans=ans+res.a[len-base+i+1][j]*dp[r][c];
}
}
cout<return 0;
}
E - Fast Matrix Calculation
如果直接根据题意计算的话,最后的矩阵大小可达1000*1000,存都存不了。所以我们换种方式就好了。
我们要计算(A*B)^(N * N),其实该式等于
A*(B A)^(N *N-1) B(数学渣表示一开始根本没想到。)
那么现在的矩阵大小就变成了6*6的了。
#include
using namespace std;
const int mod=6;
int A[1005][10],B[10][1005],C[1005][1005],ans[1005][1005];
struct M
{
int n, m;
int a[10][10];
M(int _n = 0) { n = m = _n;memset(a, 0, sizeof(a)); }
M(int _n, int _m) { n = _n, m = _m;memset(a, 0, sizeof(a)); }
void mem(int _n = 0) { n = m = _n, memset(a, 0, sizeof(a)); }
void mem(int _n, int _m) { n = _n, m = _m;memset(a, 0, sizeof(a)); }
friend M operator*(M a, M b)
{
M c(a.n,b.m);
for (int k = 1;k <= a.m;k++)
for (int i = 1;i <= a.n;i++)
for (int j = 1;j <= b.m;j++)
(c.a[i][j] += (a.a[i][k] * b.a[k][j])%mod)%=mod;
return c;
}
void make_I(int _n)
{
n = m = _n;
memset(a, 0, sizeof(a));
for (int i = 1;i <= n;i++)a[i][i] = 1;
}
void out()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
cout<' ';
cout<int num,M a)
{
M res;
res.make_I(a.n);
M tmp=a;
while(num)
{
if(num%2)res=res*tmp;
num/=2;
tmp=tmp*tmp;
}
return res;
}
int main()
{
int N,K;
while(~scanf("%d %d",&N,&K)&&N)
{
memset(C,0,sizeof(C));
memset(ans,0,sizeof(ans));
for(int i=1;i<=N;i++)
for(int j=1;j<=K;j++)
scanf("%d",&A[i][j]);
for(int i=1;i<=K;i++)
for(int j=1;j<=N;j++)
scanf("%d",&B[i][j]);
M c(K);
for(int k=1;k<=N;k++)
for(int i=1;i<=K;i++)
for(int j=1;j<=K;j++)
(c.a[i][j]+=B[i][k]*A[k][j]%mod)%=mod;
//c.out();
M tmp=quick_mul(N*N-1,c);
for(int k=1;k<=K;k++)
for(int i=1;i<=N;i++)
for(int j=1;j<=K;j++)
(C[i][j]+=A[i][k]*tmp.a[k][j]%mod)%=mod;
for(int k=1;k<=K;k++)
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
(ans[i][j]+=C[i][k]*B[k][j]%mod)%=mod;
int res=0;
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
res+=ans[i][j];
printf("%d\n",res);
}
return 0;
}
H - Power of Matrix
如果直接计算的话那么复杂度为k*n^3,会爆炸,所以我们得想个方法进行优化。
设 S(k)=A+A2+A3+...+Ak S ( k ) = A + A 2 + A 3 + . . . + A k ,当k为偶数时, S(k)=(A+A2+A3+..+Ak/2)∗(1+Ak/2) S ( k ) = ( A + A 2 + A 3 + . . + A k / 2 ) ∗ ( 1 + A k / 2 ) ,同理k为奇数的时候也可以这样优化,那么复杂度变成了log(k)*n^3.
#include
using namespace std;
typedef long long ll;
const int maxn=45;
const int mod=10;
struct M
{
int n, m;
int a[maxn][maxn];
M(int _n = 0)
{
n = m = _n;
memset(a, 0, sizeof(a));
}
M(int _n, int _m)
{
n = _n, m = _m;
memset(a, 0, sizeof(a));
}
void mem(int _n = 0)
{
n = m = _n, memset(a, 0, sizeof(a));
}
void mem(int _n, int _m)
{
n = _n, m = _m;
memset(a, 0, sizeof(a));
}
friend M operator*(M a, M b)
{
M c(a.n,b.m);
for (int k = 1; k <= a.m; k++)
for (int i = 1; i <= a.n; i++)
for (int j = 1; j <= b.m; j++)
(c.a[i][j] += (a.a[i][k] * b.a[k][j])%mod)%=mod;
return c;
}
friend M operator+(M a, M b)
{
M c(a.n,a.m);
for (int i = 1; i <= a.n; i++)
for (int j = 1; j <= a.m; j++)
c.a[i][j]=(a.a[i][j] + b.a[i][j])%mod;
return c;
}
void make_I(int _n)
{
n = m = _n;
memset(a, 0, sizeof(a));
for (int i = 1; i <= n; i++)a[i][i] = 1;
}
void out()
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
printf("%d",a[i][j]%mod);
if(j!=m)printf(" ");
else puts("");
}
}
}
};
M A;
int n,k;
M quick_mul(int num,M a)
{
M res;
res.make_I(a.n);
M tmp=a;
while(num)
{
if(num%2)res=res*tmp;
num/=2;
tmp=tmp*tmp;
}
return res;
}
M dfs(int num)
{
if(num==1)return A;
if(num%2)
{
M tmp=quick_mul(num,A);
return tmp+dfs(num-1);
}
else
{
M tmp=quick_mul(num/2,A);
M tmp2;
tmp2.make_I(A.n);
tmp=tmp+tmp2;
return tmp*dfs(num/2);
}
}
int main()
{
while(~scanf("%d %d",&n,&k)&&n)
{
A.mem(n);
ll tmp;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
{
scanf("%lld",&tmp);
A.a[i][j]=tmp%10;
}
M F(n);
F=dfs(k);
F.out();
puts("");
}
}
I - Contemplation! Algebra
设 S(n)=an+bn S ( n ) = a n + b n
我们可以用a+b,a*b找出S(n)的递推关系。找出关系后直接用矩阵快速幂即可。
#include
using namespace std;
typedef long long ll;
const int maxn=5;
ll p,q,n;
struct M
{
int n, m;
ll a[maxn][maxn];
M(int _n = 0) { n = m = _n;memset(a, 0, sizeof(a)); }
M(int _n, int _m) { n = _n, m = _m;memset(a, 0, sizeof(a)); }
void mem(int _n = 0) { n = m = _n, memset(a, 0, sizeof(a)); }
void mem(int _n, int _m) { n = _n, m = _m;memset(a, 0, sizeof(a)); }
friend M operator*(M a, M b)
{
M c(a.n,b.m);
for (int k = 1;k <= a.m;k++)
for (int i = 1;i <= a.n;i++)
for (int j = 1;j <= b.m;j++)
c.a[i][j] += (a.a[i][k] * b.a[k][j]);
return c;
}
void make_I(int _n)
{
n = m = _n;
memset(a, 0, sizeof(a));
for (int i = 1;i <= n;i++)a[i][i] = 1;
}
};
M quick_mul(int num,M a)
{
M res;
res.make_I(a.n);
M tmp=a;
while(num)
{
if(num%2)res=res*tmp;
num/=2;
tmp=tmp*tmp;
}
return res;
}
int main()
{
while(scanf("%lld %lld %lld",&p,&q,&n)==3)
{
if(n==0)
{
puts("2");
continue;
}
else if(n==1)
{
printf("%lld\n",p);
continue;
}
M it(2);
it.a[1][1]=p,it.a[1][2]=-q;
it.a[2][1]=1;
M res=quick_mul(n-2,it);
ll ans=0;
ll tmp=p*p-2*q;
ans=res.a[1][1]*tmp+res.a[1][2]*p;
printf("%lld\n",ans);
}
return 0;
}
J - Cellular Automaton
做的时候发现结构体的矩阵根本存不了,就将数组放外面,看时间给了18s,以为T不了,结果T了。看了题解才知道什么是循环矩阵,关于循环矩阵,博主会在下一篇博客说明。循环矩阵的计算只需要n^2,这样就不会T了。
#include
using namespace std;
typedef long long ll;
const int maxn=505;
int N,M,D,K;
#define ceil cl
struct Mat
{
ll arr[maxn];
};
Mat ceil,x;
Mat mul_mat(const Mat&a,const Mat&b)
{
Mat ans;
memset(ans.arr,0,sizeof(ans.arr));
for(int i=0;ifor(int j=0;jreturn ans;
}
void pow_mat(int n)
{
Mat ans=x;
while(n)
{
if(n&1)
ans=mul_mat(ans,x);
x=mul_mat(x,x);
n>>=1;
}
x=ans;
}
int main()
{
while(~scanf("%d %d %d %d",&N,&M,&D,&K))
{
for(int i=0;iscanf("%lld",&ceil.arr[i]);
memset(x.arr,0,sizeof(x));
for(int i=-D;i<=D;i++)
x.arr[(i+N)%N]=1;
pow_mat(K-1);
for(int i=0;iif(i)printf(" ");
ll ret=0;
for(int j=0;jceil.arr[j]*x.arr[(j-i+N)%N])%M;
printf("%lld",ret);
}
puts("");
}
return 0;
}
M - So Easy!
数学渣表示根本不会做这个题。
我们要求 (a+b√)n ( a + b ) n 向上取整的值,用脚趾头想一想如果直接快速幂的话,肯定会因为精度问题输出错误答案。所以应该怎么做呢?
这里有一个定义,就是共轭, (a+b√)n ( a + b ) n 和 (a−b√)n ( a − b ) n 相加必定是个整数。题目给的b的范围很有意思,在 (a−1)2到a2 ( a − 1 ) 2 到 a 2 之间,那么 a−b√ a − b 必定是个小数,n次幂之后也只会是小数,所以我们实际要求的是 Sn=(a+b√)n+(a−b√)n S n = ( a + b ) n + ( a − b ) n 。
到了现在,我们只需要求出 Sn S n 与它之前的递推式即可。这个留给读者啦。
#include
using namespace std;
int mod;
struct M
{
int n, m;
int a[3][3];
M(int _n = 0)
{
n = m = _n;
memset(a, 0, sizeof(a));
}
M(int _n, int _m)
{
n = _n, m = _m;
memset(a, 0, sizeof(a));
}
void mem(int _n = 0)
{
n = m = _n, memset(a, 0, sizeof(a));
}
void mem(int _n, int _m)
{
n = _n, m = _m;
memset(a, 0, sizeof(a));
}
friend M operator*(M a, M b)
{
M c(a.n,b.m);
for (int k = 1; k <= a.m; k++)
for (int i = 1; i <= a.n; i++)
for (int j = 1; j <= b.m; j++)
(c.a[i][j] += (1LL*a.a[i][k] * b.a[k][j])%mod)%=mod;
return c;
}
void make_I(int _n)
{
n = m = _n;
memset(a, 0, sizeof(a));
for (int i = 1; i <= n; i++)a[i][i] = 1;
}
};
M quick_mul(int num,M a)
{
M res;
res.make_I(a.n);
M tmp=a;
while(num)
{
if(num%2)res=res*tmp;
num/=2;
tmp=tmp*tmp;
}
return res;
}
int main()
{
int a,b,n;
while(cin>>a>>b>>n>>mod)
{
int ans;
if(n==1)
ans=2*a;
else
{
M A(2);
A.a[1][1]=2*a%mod;
A.a[1][2]=(b-a*a)%mod;
A.a[2][1]=1;
int times=n-1;
M res=quick_mul(times,A);
int tmp=2*a%mod;
ans=res.a[1][1]*tmp%mod+res.a[1][2]*2%mod;
}
printf("%d\n",(ans%mod+mod)%mod);
}
}
N - Yet Another Number Sequence
这题第一次碰见肯定不会做。。太难了。
真正让我感觉到了数学之美。
我们一步一步的推吧。
An+1(k)=Fn+1∗(n+1)k A n + 1 ( k ) = F n + 1 ∗ ( n + 1 ) k
由牛顿二项式定理可得
(n+1)k=C0k∗n0+C1k∗n1+C2k∗n2+...+Ckk∗nk=∑ki=0Cik∗ni ( n + 1 ) k = C k 0 ∗ n 0 + C k 1 ∗ n 1 + C k 2 ∗ n 2 + . . . + C k k ∗ n k = ∑ i = 0 k C k i ∗ n i
所以可得
An+1(k)=Fn+1∗∑ki=0Cik∗ni A n + 1 ( k ) = F n + 1 ∗ ∑ i = 0 k C k i ∗ n i
又 Fn+1=Fn+Fn−1 F n + 1 = F n + F n − 1
所以 An+1(k)=Fn∗∑ki=0Cik∗ni+Fn−1∗∑ki=0Cik∗ni A n + 1 ( k ) = F n ∗ ∑ i = 0 k C k i ∗ n i + F n − 1 ∗ ∑ i = 0 k C k i ∗ n i
为了方便计算,我们设 u(n+1,k)=An+1(k),v(n+1,i)=Fn∗(n+1)i u ( n + 1 , k ) = A n + 1 ( k ) , v ( n + 1 , i ) = F n ∗ ( n + 1 ) i
那么原式可化为
u(n+1,k)=∑ki=0Cik∗u(n,i)+v(n,i)∗∑ki=0Cik u ( n + 1 , k ) = ∑ i = 0 k C k i ∗ u ( n , i ) + v ( n , i ) ∗ ∑ i = 0 k C k i
又 v(n+1,k)=Fn∗(n+1)i=Fn∗∑ki=0Cik∗ni=∑ki=0Ciku(n,i) v ( n + 1 , k ) = F n ∗ ( n + 1 ) i = F n ∗ ∑ i = 0 k C k i ∗ n i = ∑ i = 0 k C k i u ( n , i )
所以最终原式可化为
u(n+1,k)=∑ki=0Cik∗u(n,i)+v(n,i)∑ki=0Cik u ( n + 1 , k ) = ∑ i = 0 k C k i ∗ u ( n , i ) + v ( n , i ) ∑ i = 0 k C k i
v(n,k)=∑ki=0Ciku(n−1,i) v ( n , k ) = ∑ i = 0 k C k i u ( n − 1 , i )
贴一个别人写好的矩阵。
#include
using namespace std;
const int maxn=85;
const int mod=1e9+7;
typedef long long ll;
int C[45][45];
void init()
{
C[0][0]=1;
for(int i=1;i<=40;i++)C[i][0]=C[i][i]=1;
for(int i=2;i<=40;i++)
for(int j=1;j1][j]+C[i-1][j-1])%mod;
//cout<
}
}
struct M
{
int n, m;
int a[maxn][maxn];
M(int _n = 0) { n = m = _n;memset(a, 0, sizeof(a)); }
M(int _n, int _m) { n = _n, m = _m;memset(a, 0, sizeof(a)); }
void mem(int _n = 0) { n = m = _n, memset(a, 0, sizeof(a)); }
void mem(int _n, int _m) { n = _n, m = _m;memset(a, 0, sizeof(a)); }
friend M operator*(M a, M b)
{
M c(a.n,b.m);
for (int k = 1;k <= a.m;k++)
for (int i = 1;i <= a.n;i++)
for (int j = 1;j <= b.m;j++)
(c.a[i][j] += (1LL*a.a[i][k] * b.a[k][j])%mod)%=mod;
return c;
}
void make_I(int _n)
{
n = m = _n;
memset(a, 0, sizeof(a));
for (int i = 1;i <= n;i++)a[i][i] = 1;
}
void out()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
cout<' ' ;
cout<while(num)
{
if(num%2)res=res*tmp;
num/=2;
tmp=tmp*tmp;
}
return res;
}
int main()
{
init();
//cout<
ll n;
int k;
cin>>n>>k;
M A(2*k+3);
A.a[1][1]=1;
int nowk=0;
for(int i=2;i<=2*k+3;i++,nowk=(nowk+1)%(k+1))
A.a[1][i]=C[k][nowk];
int r=0;
for(int i=2;i<=k+2;i++,r++)
{
for(int j=2;j-2<=r;j++)
{
A.a[i][j]=C[r][j-2];
A.a[i][j+k+1]=C[r][j-2];
}
}
r=0;
for(int i=k+3;i<=2*k+3;i++,r++)
{
for(int j=2;j-2<=r;j++)
A.a[i][j]=C[r][j-2];
}
//A.out();
M B(2*k+3,1);
for(int i=1;i<=k+2;i++)
B.a[i][1]=1;
for(int i=k+3;i<=2*k+3;i++)
B.a[i][1]=1;
ll times=n-1;
M res=quick_mul(times,A);
//res.out();
M ans=res*B;
cout<1 ][1]<
P - Construct a Matrix
这题的关键点在于如何构造矩阵。
观察可得当计算出来的矩阵边长为奇数时构造不出来。
所以只有偶数的时候才能构造。
构造方法为左上部分全部为1,右下部分全部为-1,中间对角线一半为0,一半为1。
#include
#include
#include
#include
using namespace std;
int mod;
struct M
{
int n, m;
int a[5][5];
M(int _n = 0) { n = m = _n;memset(a, 0, sizeof(a)); }
M(int _n, int _m) { n = _n, m = _m;memset(a, 0, sizeof(a)); }
void mem(int _n = 0) { n = m = _n, memset(a, 0, sizeof(a)); }
void mem(int _n, int _m) { n = _n, m = _m;memset(a, 0, sizeof(a)); }
friend M operator*(M a, M b)
{
M c(a.n,b.m);
for (int k = 1;k <= a.m;k++)
for (int i = 1;i <= a.n;i++)
for (int j = 1;j <= b.m;j++)
(c.a[i][j] += (a.a[i][k] * b.a[k][j])%mod)%=mod;
return c;
}
void make_I(int _n)
{
n = m = _n;
memset(a, 0, sizeof(a));
for (int i = 1;i <= n;i++)a[i][i] = 1;
}
};
M quick_mul(int num,M a)
{
M res;
res.make_I(a.n);
M tmp=a;
while(num)
{
if(num%2)res=res*tmp;
num/=2;
tmp=tmp*tmp;
}
return res;
}
int main()
{
int T;
scanf("%d",&T);
M A(3);
A.a[1][1]=A.a[1][2]=A.a[1][3]=A.a[2][2]=A.a[2][3]=A.a[3][2]=1;
int cas=1;
while(T--)
{
int L;
int n,m;
scanf("%d %d",&n,&m);
printf("Case %d: ",cas++);
mod=m;
M res=quick_mul(n-2,A);
L=0;
L=((res.a[1][1]*2%mod+res.a[1][2])%mod+res.a[1][3])%mod;
if(L%2||L==0)
puts("No");
else
{
puts("Yes");
for(int i=1;i<=L;i++)
{
for(int j=1;j<=L;j++)
{
if(i+j1)
{
printf("1");
}
else if(i+j==L+1)
{
if(i<=L/2)
printf("0");
else
printf("1");
}
else
printf("-1");
if(j!=L)
printf(" ");
}
puts("");
}
}
}
}
R - M斐波那契数列
分开计算a和b的指数,容易发现他们的指数就是斐波那契数列。
另外求出来的指数会很大,那该怎么办呢?
当模数为质数时,由费马小定理得 ap−1≡1(mod p) a p − 1 ≡ 1 ( m o d p )
所以我们可以将其指数模上p-1.
#include
#include
#include
#include
using namespace std;
const int mod=1000000007;
typedef long long ll;
struct M
{
int n, m;
ll a[3][3];
M(int _n = 0) { n = m = _n;memset(a, 0, sizeof(a)); }
M(int _n, int _m) { n = _n, m = _m;memset(a, 0, sizeof(a)); }
void mem(int _n = 0) { n = m = _n, memset(a, 0, sizeof(a)); }
void mem(int _n, int _m) { n = _n, m = _m;memset(a, 0, sizeof(a)); }
friend M operator*(M a, M b)
{
M c(a.n,b.m);
for (int k = 1;k <= a.m;k++)
for (int i = 1;i <= a.n;i++)
for (int j = 1;j <= b.m;j++)
(c.a[i][j] += (a.a[i][k] * b.a[k][j])%(mod-1))%=(mod-1);
return c;
}
void make_I(int _n)
{
n = m = _n;
memset(a, 0, sizeof(a));
for (int i = 1;i <= n;i++)a[i][i] = 1;
}
};
M quick_mul(int num,M a)
{
M res;
res.make_I(a.n);
M tmp=a;
while(num)
{
if(num%2)res=res*tmp;
num/=2;
tmp=tmp*tmp;
}
return res;
}
ll FM(int times,int num)
{
ll ans=1;
ll tmp=num;
while(times)
{
if(times%2)ans=ans*tmp%mod;
times/=2;
tmp=tmp*tmp%mod;
}
return ans;
}
int main()
{
int a,b,n;
M A(2);
A.a[1][1]=A.a[1][2]=A.a[2][1]=1;
while(cin>>a>>b>>n)
{
if(n==0)
{
cout<else if(n==1)
cout<else
{int times=n-1;
M B=quick_mul(times,A);
ll ans=0;
ans=FM(B.a[1][2],a)*FM(B.a[1][1],b)%mod;
cout<return 0;
}
S - Arc of Dream
将 ai∗bi a i ∗ b i 拆开计算从而得到它的递推式,接着进行矩阵快速幂即可得到答案。
博主智障的把N传参到一个int类型的函数中,以至于一直wa,对拍发现大数据才会有问题,但看该取模的地方都取模了,所以找了一下午的bug。。最后才发现传参的时候爆了。。
#include
using namespace std;
typedef unsigned long long ll;
const ll mod=1000000007;
struct M
{
int n, m;
ll a[10][10];
M(int _n = 0)
{
n = m = _n;
memset(a, 0, sizeof(a));
}
M(int _n, int _m)
{
n = _n, m = _m;
memset(a, 0, sizeof(a));
}
void mem(int _n = 0)
{
n = m = _n, memset(a, 0, sizeof(a));
}
void mem(int _n, int _m)
{
n = _n, m = _m;
memset(a, 0, sizeof(a));
}
friend M operator*(M a, M b)
{
M c(a.n,b.m);
for (int k = 1; k <= a.m; k++)
for (int i = 1; i <= a.n; i++)
for (int j = 1; j <= b.m; j++)
(c.a[i][j] += (a.a[i][k] * b.a[k][j])%mod)%=mod;
return c;
}
void make_I(int _n)
{
n = m = _n;
memset(a, 0, sizeof(a));
for (int i = 1; i <= n; i++)a[i][i] = 1;
}
void out()
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
cout<' ';
cout<while(num)
{
if(num%2)res=res*tmp;
num/=2;
tmp=tmp*tmp;
}
return res;
}
M a;
ll N,A0,AX,AY,B0,BX,BY;
ll first[10];
void init()
{
// N%=(mod-1);
A0%=mod,AX%=mod,AY%=mod;
B0%=mod,BX%=mod,BY%=mod;
a.mem(6);
a.a[1][1]=1;
a.a[1][2]=a.a[2][2]=AX*BX%mod;
a.a[1][3]=a.a[2][3]=AX*BY%mod;
a.a[1][4]=a.a[2][4]=AY*BX%mod;
a.a[1][5]=a.a[2][5]=BY;
a.a[3][3]=AX,a.a[3][5]=1;
a.a[4][4]=BX,a.a[4][6]=1;
a.a[5][5]=1;
a.a[6][6]=1;
//a.out();
//a=a*a;
//a.out();
first[1]=A0*B0%mod;
first[2]=A0*B0%mod;
first[3]=A0;
first[4]=B0;
first[5]=AY;
first[6]=BY;
}
int main()
{
//freopen("D:\\1.txt","r",stdin);
//freopen("D:\\2.txt","w",stdout);
while(~scanf("%lld",&N))
{
scanf("%lld %lld %lld %lld %lld %lld",&A0,&AX,&AY,&B0,&BX,&BY);
init();
if(N==0)
{
puts("0");
continue;
}
ll times=N-1;
M res=quick_mul(times,a);
ll ans=0;
for(int i=1; i<=6; i++)
{
ans=ans+res.a[1][i]*first[i]%mod;
ans%=mod;
}
printf("%lld\n",ans);
}
}
矩阵只是一个板子,最重要的是需要自己推出递推式。
最近写题老有bug,打比赛的时候都不敢交题,怕被罚时。经过本专题的bug洗礼之后,博主内心变得无比平静,罚时就罚时吧,QTMD!