[TJOI2017]可乐(数据加强版)
矩阵乘法优化图上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;
}
一如既往,万事胜意