矩阵乘法Ⅱ

可乐

第一眼以为和概率期望什么的有关系,吓得不轻(我对那个东西有生理厌恶的),如果再来一个迷失游乐园之类的那就不好了。

不过定睛一看,蓝题。应该还好。朴素的想就是一个奇怪的分层图。然后玄学吸几口 \(O_2\) 就可以水过去。顺便提一下,由于脑残了,边数开的不是太大,忽略了有额外边的存在,调了好久【汗颜】……

#include<cstdio>
//#define zczc
const int N=1000010;
const int M=31;
const int mod=2017;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar(); }
    wh*=f;return;
}

int m,n,want;
struct edge{
	int t,next;
}e[310];
int esum,head[M];
inline void add(int fr,int to){
	esum++;
	e[esum].t=to;
	e[esum].next=head[fr];
	head[fr]=esum;
	return;
}

inline void Add(int &s1,int s2){
	s1+=s2;if(s1>=mod)s1-=mod;return;
}
int f[N][M];

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	
	int s1,s2;
	read(m);read(n);
	for(int i=1;i<=n;i++){
		read(s1);read(s2);
		add(s1,s2);add(s2,s1);
	}
	for(int i=0;i<=m;i++){
		add(i,i);
		if(i^0)add(i,0);
	}
	read(want);
	f[0][1]=1;
	for(int i=0;i<want;i++){
		for(int wh=0;wh<=m;wh++){
			for(int j=head[wh];j;j=e[j].next){
				Add(f[i+1][e[j].t],f[i][wh]);
			}
		}
	}
	int ans=0;
	for(int i=0;i<=m;i++)Add(ans,f[want][i]);
	printf("%d\n",ans);
	
	return 0;
}

但做人不能如此不道德,勾引评测姬以换取 \(AC\) 的行为是极其不正当的。

题目标签以及题解区里有矩阵乘法的影子,那就看一下吧。

上面那个算法慢在哪里,慢就慢在中间那个三重循环。假如我们把每一个f[i]当成一个1\(\times ?\) 的矩阵,那么我们需要做的就是快速地从一个矩阵转向另一个矩阵,得到答案。想到用矩阵乘法。然后推导结论,快速幂即可。

#include<cstdio>
//#define zczc
const int N=1000010;
const int M=31;
const int mod=2017;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar(); }
    wh*=f;return;
}

int m,n,want;
struct node{
	int l1,l2,a[M][M];
}newone;
inline void add(int &s1,int s2){
	s1+=s2;s1%=mod;return;
}
inline node operator *(node s1,node s2){
	node an=newone;
	an.l1=s1.l1,an.l2=s2.l2;
	for(int i=0;i<=an.l1;i++){
		for(int j=0;j<=an.l2;j++){
			for(int k=0;k<=an.l2;k++){
				add(an.a[i][j],s1.a[i][k]*s2.a[k][j]);
			}
		}
	}
	return an;
}
inline node pow(node s1,int s2){
	if(s2==1)return s1;
	node an=pow(s1,s2>>1);
	if(s2&1)return an*an*s1;
	else return an*an;
}

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	
	int s1,s2;
	node s=newone;
	read(m);read(n);
	s.l1=s.l2=m;
	for(int i=1;i<=n;i++){
		read(s1);read(s2);
		s.a[s1][s2]=s.a[s2][s1]=1;
	}
	for(int i=0;i<=m;i++){
		s.a[i][0]=1;
		if(i^0)s.a[i][i]=1;
	}
	read(want);
	node an=pow(s,want);
	int ans=0;
	for(int i=0;i<=m;i++)add(ans,an.a[1][i]);
	printf("%d\n",ans);
	
	return 0;
}
上一篇:搜索Ⅰ


下一篇:题解 洛谷 P3369 【模板】普通平衡树