题目大意:给定一张图
,求
题解:
一些显然的做法是把那个幂次拆成斯特林数然后就是要求从路径上再选出若干条不同的边的方案数,这个就可以直接拿来倍增做到O(n^5lgk)了。
考虑直接对这个倍增:
因此维护
即可。
每次算一个
需要
次加法和
次乘法,因此算每个
复杂度是
,因此总复杂度
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define mod 1000000007
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
inline int fast_pow(int x,int k,int ans=1) { for(;k;k>>=1,x=(lint)x*x%mod) (k&1)?ans=(lint)ans*x%mod:0;return ans; }
const int N=52;
namespace MAT{
int n;
struct mat{
int v[N][N];
inline int& operator()(int x,int y) { return v[x][y]; }
inline int clear() { rep(i,1,n) memset(v[i],0,sizeof(int)*(n+1));return 0; }
inline mat operator*(const mat &b)const
{
const mat &a=*this;static mat res;res.clear();
rep(i,1,n) rep(j,1,n)
{
int v=0,k=1;ull w=0;
#define P(k) (ull)a.v[i][k]*b.v[k][j]
for(;k+15<=n;k+=16)
v=(v+P(k+0)+P(k+1)+P(k+2)+P(k+3)+P(k+4)+P(k+5)+P(k+6)+P(k+7)
+P(k+8)+P(k+9)+P(k+10)+P(k+11)+P(k+12)+P(k+13)+P(k+14)+P(k+15))%mod;
for(;k<=n;k++) w+=P(k);res.v[i][j]=(v+w)%mod;
#undef P
}
return res;
}
inline mat& operator*=(const mat &b) { return (*this)=(*this)*b,*this; }
inline mat operator*(int x)const
{
static mat res;res=*this;
rep(i,1,n) rep(j,1,n) res.v[i][j]=(lint)res.v[i][j]*x%mod;
return res;
}
inline mat& operator*=(int x) { return (*this)=(*this)*x,*this; }
inline mat operator+(const mat &b)const
{
static mat res;res=*this;
rep(i,1,n) rep(j,1,n) { int &x=res.v[i][j];x+=b.v[i][j],(x>=mod?x-=mod:0); }
return res;
}
inline mat& operator+=(const mat &b) { return (*this)=(*this)+b,*this; }
}I;
inline mat operator*(int x,const mat &b) { return b*x; }
inline int _init(int _n) { n=_n;rep(i,1,n) I(i,i)=1;return 0; }
}
using MAT::I;using MAT::mat;mat g;
namespace BIGMAT{
int T,C[N][N],mi[N];
inline int _init(int _T)
{
T=_T;rep(i,0,T) C[i][0]=1;
rep(i,1,T) rep(j,1,i) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
return 0;
}
struct bigmat{
mat g,v[N];int len;
inline int clear() { rep(i,0,T) v[i].clear();return len=0; }
inline bigmat operator*(const bigmat &b)const
{
const bigmat &a=*this;static bigmat res;res.clear();
if(!a.len) return b;res.g=a.g*b.g;
rep(i,mi[0]=1,T) mi[i]=(lint)mi[i-1]*a.len%mod;
rep(t,0,T)
{
rep(j,0,t) res.v[t]+=(lint)C[t][j]*mi[t-j]%mod*b.v[j];
res.v[t]*=g,res.v[t]+=a.v[t];
}
return res.len=a.len+b.len,res;
}
inline bigmat operator*=(const bigmat &b) { return (*this)=(*this)*b,*this; }
inline bigmat operator+(const bigmat &b)
{
static bigmat res;res=*this;
rep(i,0,T) res.v[i]+=b.v[i];
return res;
}
inline bigmat operator+=(const bigmat &b) { return (*this)=(*this)+b,*this; }
inline int& operator()(int x,int y,int z) { return v[x](y,z); }
};
}using BIGMAT::bigmat;bigmat G,ans;
inline int fast_pow(bigmat &x,int k) { for(;k;k>>=1,x*=x) if(k&1) ans*=x;return 0; }
int main()
{
int n=inn(),k=inn(),q=inn(),T=inn();
MAT::_init(n);rep(i,1,n) rep(j,1,n) g(i,j)=inn();
if(k<=1) { while(q--) printf("0\n");return 0; }
rep(i,0,T) ans.v[i]=I,G.v[i]=g;ans.g=I,G.g=g,ans.len=0,G.len=1;
BIGMAT::_init(T),fast_pow(G,k-1);
for(int x,y;q;q--) x=inn(),y=inn(),printf("%d\n",ans(T,x,y));
}