bzoj1875 [SDOI2009]HH去散步
bzoj1875 [SDOI2009]HH去散步
原题链接
题解
如果没有边方面的限制这就是道矩乘大水题。。。
然而有
所以考虑边->点,统计一条边走向另一条边的方案。
把无向边拆成两条有向边,枚举点,再枚举终点是他的边,再枚举起点是他的边。。。
就可以了,再把矩阵变成(t-1)次方,枚举起点的边终点的边统计答案。
Code
// It is made by XZZ
#include<cstdio>
#include<algorithm>
#define Fname "bzoj1875"
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
#define mod 45989
typedef long long ll;
il ll gi(){
rg ll x=0;rg char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x;
}
int n,m;
struct Mat{
ll s[122][122];
Mat(){rep(i,1,m)rep(j,1,m)s[i][j]=0;}
};
il vd Add(ll&a,ll b){a=(a+b)%mod;}
Mat operator +(Mat a,Mat b){
rep(i,1,m)rep(j,1,m)Add(a.s[i][j],b.s[i][j]);
return a;
}
Mat operator *(Mat a,Mat b){
Mat ret;
rep(i,1,m)rep(j,1,m)rep(l,1,m)Add(ret.s[i][j],a.s[i][l]*b.s[l][j]%mod);
return ret;
}
vd operator +=(Mat&a,Mat b){a=a+b;}
vd operator *=(Mat&a,Mat b){a=a*b;}
Mat operator ^(Mat a,ll b){
Mat ret=a;--b;
while(b){
if(b&1)ret*=a;
a*=a,b>>=1;
}return ret;
}
vd operator ^=(Mat&a,ll b){a=a^b;}
namespace e{
int id=0,fir[51],nxt[121],dis[121];
il vd add(int a,int b){nxt[++id]=fir[a],fir[a]=id,dis[id]=b;}
}
#define rev(o) ((o)&1?(o)+1:(o)-1)
int main(){
// freopen(Fname".in","r",stdin);
// freopen(Fname".out","w",stdout);
n=gi(),m=gi();
ll t=gi();
int S=gi()+1,T=gi()+1,a,b;
using namespace e;
rep(i,1,m)a=gi()+1,b=gi()+1,add(a,b),add(b,a);
m<<=1;
Mat s;
rep(i,1,n)erep(x,i)erep(y,i)if(x!=y)s.s[rev(y)][x]=s.s[rev(x)][y]=1;
s^=t-1;
ll ans=0;
erep(i,S)erep(j,T)Add(ans,s.s[i][rev(j)]);
printf("%lld\n",ans);
return 0;
}
/*
4 5 3 0 0
0 1
0 2
0 3
2 1
3 2
*/
PS.常数优化真TM逼了狗。。。把ll mod=45989
改成#define mod 45989
就50->100
博主是蒟蒻,有问题请指出,谢谢!
本博客中博文均为原创,未经博主允许请勿随意转载,谢谢。
本博客中博文均为原创,未经博主允许请勿随意转载,谢谢。