题目大意:给一张图,多次询问两点间长度在[L,R]的路径数。
n
≤
100
,
q
≤
100
,
R
−
L
≤
200
n\le100,q\le100,R-L\le200
n≤100,q≤100,R−L≤200
题解:
答案是
∑
i
=
L
R
G
i
\sum_{i=L}^R G^i
∑i=LRGi,你显然可以跑一个矩乘套矩乘之类的东西。
暴力是
O
(
q
n
3
(
lg
n
+
R
−
L
)
)
O(qn^3(\lg n+R-L))
O(qn3(lgn+R−L))的,考虑优化。
不妨令最终答案是
A
A
A,那么显然
A
x
,
y
=
(
B
A
)
1
,
y
A_{x,y}=(BA)_{1,y}
Ax,y=(BA)1,y,其中
B
B
B是一个行向量,且只有第一行第x个位置是1.
然后预处理
G
2
k
G^{2^k}
G2k,然后每次询问左乘一个B再去做乘法即可做到
O
(
n
3
lg
n
+
q
n
2
(
lg
n
+
R
−
L
)
)
O(n^3\lg n+qn^2(\lg n+R-L))
O(n3lgn+qn2(lgn+R−L))。
#include<bits/stdc++.h>
#define gc getchar()
#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 2333
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#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;
}
const int N=45;
struct matrix{
int v[N][N],n,m;matrix(int _n=0,int _m=0) { init(_n,_m); }
inline int init(int _n,int _m=0) { n=_n,m=_m;if(!m) m=n;rep(i,1,n) memset(v[i],0,sizeof(int)*(m+1));return 0; }
inline matrix operator*(const matrix &b)const
{
const matrix &a=*this;matrix c(n,b.m);
rep(i,1,n) rep(k,1,m) rep(j,1,b.m) c.v[i][j]+=a.v[i][k]*b.v[k][j];
rep(i,1,n) rep(j,1,b.m) (c.v[i][j]>=mod?c.v[i][j]%=mod:0);return c;
}
inline matrix& operator*=(const matrix &b) { return (*this)=(*this)*b; }
}G[31],A;
inline matrix calc(int p,int n,int k)
{
matrix ans;ans.init(1,n),ans.v[1][p]=1;
for(int i=0;k;k>>=1,i++) if(k&1) ans*=G[i];
return ans;
}
int main()
{
int n=inn(),m=inn(),x,y,l,r,ans;G[0].init(n);
rep(i,1,m) x=inn(),y=inn(),G[0].v[x][y]=G[0].v[y][x]=1;
for(int k=1e9,i=1;k;k>>=1,i++) G[i]=G[i-1]*G[i-1];
for(int q=inn();q;q--)
{
x=inn(),y=inn(),l=inn(),r=inn();
A=calc(x,n,l),ans=A.v[1][y];
rep(i,l+1,r) A*=G[0],ans+=A.v[1][y];
printf("%d\n",ans%mod);
}
return 0;
}