题意:第一行给出k,n,第二行2*k个数字,分别是a1,a2…ak 以及 f1,f2…fk
已知满足
f1 = a1 * p1 + a2 * p2 + a3 * p3…+ ak * pk
f2 = a2 * p1 + a3 * p2 + a4 * p3…+ f1 * pk
…
fk = ak * p1 + f1 * p2 + f2 * p3…+ fk-1 * pk
以此类推的k个式子,求f的前n项和
思路:正解应该是高斯消元+矩阵快速幂,求出p1-pk,但是高斯消元过程中可能会出现小数,利用费马小定理求出逆元,然后矩阵快速幂进行计算。。但是后来完事以后看网上题解发现好多人水过了,,好像是f在第k项以后就不会变了,一直是同一个数,那么直接读入完就能o(1)算出来,,吐血,,我说怎么那么多人过呢
当时没想过这题能这么解,,也没想到高斯消元小数要怎么处理,,,矩阵快速幂写的也不利索,枯了。。太菜了还是
1.矩阵快速幂做法:
/*
构造出的初始矩阵是: ak, ak-1, ... a1, ans
每次要乘的base矩阵是:
pk 1 0 0 ... 1
pk-1 0 1 0 ...
pk-2 0 0 1 ...
...
p1 0 0 0 ... 0
0 0 0 0 ... 1
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
const int N = 100,mod=1e9+7;
ll a[N][N],tem[N*2];
ll n,k;
struct mat
{
ll a[N][N];
};
ll q_pow(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1)
ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
void gauss()
{
int c,r,n=k;
for(c=0,r=0;c<n;c++)
{
int t=r;
for(int i=r+1;i<n;i++)
if(fabs(a[i][c])>fabs(a[t][c]))
t=i;
for(int j=c;j<=n;j++)
swap(a[t][j],a[r][j]);
for(int j=n;j>=c;j--)
a[r][j]=a[r][j]*q_pow(a[r][c],mod-2),a[r][j]%=mod;
for(int i=r+1;i<n;i++)
for(int j=n;j>=c;j--)
a[i][j]-=a[r][j]*a[i][c],a[i][j]%=mod;
r++;
}
for(int i=n-1;i>=0;i--)
for(int j=i+1;j<n;j++)
a[i][n]-=a[j][n]*a[i][j],a[i][n]%=mod;
}
mat mul(mat a,mat b)
{
mat ans;
memset(ans.a,0,sizeof ans.a);
for(int i=0;i<=k;i++)
for(int j=0;j<=k;j++)
for(int r=0;r<=k;r++)
{
ans.a[i][j]+=a.a[i][r]*b.a[r][j]%mod;
ans.a[i][j]%=mod;
}
return ans;
}
mat mul_pow(mat ans,mat a,ll b)
{
while(b)
{
if(b&1)
ans=mul(ans,a);
a=mul(a,a);
b>>=1;
}
return ans;
}
ll solve()
{
mat base,ans;
memset(base.a,0,sizeof base.a);
memset(ans.a,0,sizeof ans.a);
for(int i=0;i<k;i++)
ans.a[0][i]=tem[k-i];
ll sum=0;
for(int i=1;i<k;i++)
sum=(sum+tem[i])%mod;
ans.a[0][k]=sum;
for(int i=0;i<k;i++)
base.a[i][0]=a[k-i-1][k];
for(int i=0;i<k-1;i++)
base.a[i][i+1]=1;
base.a[0][k]=base.a[k][k]=1;
ans=mul_pow(ans,base,n-k+1);
return ans.a[0][k]%mod;
}
int main()
{
int t;
cin>>t;
while(t--)
{
cin>>k>>n;
for(int i=1;i<=2*k;i++)
scanf("%lld",&tem[i]);
if(n<=2*k)
{
ll sum=0;
for(int i=1;i<=n;i++)
sum=(sum+tem[i])%mod;
cout<<sum<<endl;continue;
}
for(int i=0;i<k;i++)
for(int j=0;j<=k;j++)
a[i][j]=tem[i+j+1];
gauss();
cout<<solve()<<endl;
}
return 0;
}
2.瞎搞做法:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
int main()
{
int t;
cin>>t;
while(t--)
{
ll n,k,f,sum=0,x;
cin>>k>>n;
for(int i=1;i<=k;i++)
cin>>x,sum=(sum+x)%mod;
for(int i=1;i<=k;i++)
cin>>x;
ll ans=(sum+(n-k)%mod*x%mod)%mod;
cout<<ans<<endl;
}
return 0;
}