[TJOI2017]可乐(数据加强版)

link

矩阵乘法优化图上DP。

先要想出一个很巧妙的点。朴素的方程 \(f[i][x]=f[i-1][x]+\sum f[i-1][y]\) 而每次统计一遍爆炸个数会限制后续优化,于是考虑搞一个0号节点出来,每一个点向0连一条边即可。爆炸了之后就相当于待在那里不走了嘛。

会发现这个方程是高度重复的,每个点都会由前面的固定的一些点转移过来,于是就可以考虑进行矩阵乘法优化,用一个\(1\times N+1\)的矩阵代表第几轮之后停留在0到N号点的方案,很显然会有一个转移。捏出来一个\((N+1)\times(N+1)\)的矩阵,把方程中要加的位置对应赋一,快速幂即可。这道题似乎就不用怎么注意顺序lia。

#include<bits/stdc++.h>
//#define zczc
const int mod=2017;
const int N=110;
using namespace std;
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 a[N][N];
}newone,ss;
node operator *(node s1,node s2){
	node an=newone;
	for(int i=0;i<=m;i++){
		for(int j=0;j<=m;j++){
			for(int k=0;k<=m;k++){
				an.a[i][j]+=s1.a[i][k]*s2.a[k][j];
				an.a[i][j]%=mod;
			}
		}
	}
	return an;
}
node qpow(node s1,int s2){
	if(s2==1)return s1;
	node an=qpow(s1,s2>>1);
	if(s2&1)return an*an*s1;
	else return an*an;
}

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	
	read(m);read(n);int s1,s2;
	for(int i=0;i<=m;i++)ss.a[i][i]=ss.a[0][i]=1;
	for(int i=1;i<=n;i++){
		read(s1);read(s2);
		ss.a[s1][s2]=ss.a[s2][s1]=1;
	}
	read(want);
	node an=qpow(ss,want);
	int ans=0;
	for(int i=0;i<=m;i++)ans+=an.a[i][1];
	printf("%d",ans%mod);
	
	return 0;
}
posted @ 2022-06-21 17:17  Feyn618  阅读(29)  评论(0编辑  收藏  举报