Alice和Bob是一对好兄妹。有一天放学后,他们打算回家。但是,他们还想在路上多玩一会。现在他们有一张地图,地图上标注了小镇的所有的N个地点,以及这些地点之间的道路(道路是无向的),共M条。
在这N个地点中,有K个地点他们希望一定经过。同时,他们不希望在外面玩太久,所以他们要求经过的点总数不能超过R个,为了使得回家的路途不要太无聊,他们要求经过的点不能少于L个。他们想知道共有多少条满足要求的回家的路径。两条路径被认为是不同的,当且仅当至少有一条边不同。
如果用图论语言描述,则为:给定无向图G,求以学校为起点,家为终点,边数在L到R之间,且路径上相邻两个点均不同的路径的数量,结果对109+9取模。
输出给的大样例的答案能得10分哦,所以如果三个题我今天都输出大样例的答案,那么就和我今天得的分一样了!
今天刚出第一题还过了大样例就比较兴奋的去乱搞第二题了,就没有打这道题了(然后t1惨得20分)...
因为[l,r]区间较大,我们可以先拆分成[1,r]的答案减去[1,l-1]的答案。
又因为一个图的邻接矩阵存储的k次方,就是从任意一个点出发走k步的方案数,所以我们可以构造一个如下的矩阵套矩阵来解决要求[1,r]的问题
一般矩阵[ sum[i],a[i] ]
特殊矩阵 [ E , 0 ]
[ A, A ]
sum[i]表示走了1到i步的前缀和,a[i] 表示走了i步的前缀和,这样二者相乘就可以得到[sum[i+1],a[i+1]]了。
因为我们sum求出来的是从0到k都有可能走过的路径条数。接着为了满足k个点必须走,通过容斥原理,很容易就能想到k个点必须走的个数=总共走了[0,k]个点-总共走了[0,k-1]个点的和+[0,k-2]个点的和-....。所以我们可以通过2的i次方枚举每个点选或不选,然后统计有多少个点没选来执行上文的式子。
下附AC代码。
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define maxn 70
using namespace std;
typedef long long ll;
const ll mod=1e9+9;
int n,m,k,l,r,pos[maxn];
struct nod
{
ll n,m;
ll a[maxn][maxn];
nod() { memset(a,0,sizeof(a)); }
};
nod mul(nod a,nod b)
{
nod ans;
ans.n=a.n;ans.m=a.m;
for(int i=1;i<=ans.n;i++)
{
for(int j=1;j<=ans.m;j++)
{
for(int k=1;k<=b.n;k++)
{
ans.a[i][j]+=a.a[i][k]*b.a[k][j];
ans.a[i][j]%=mod;
}
}
}
return ans;
}
nod pow(nod a,ll p)
{
nod ans;
for(int i=1;i<=a.n;i++)
ans.a[i][i]=1;
ans.n=a.n;ans.m=a.m;
while(p)
{
if(p&1)
{
ans=mul(ans,a);
}
a=mul(a,a);
p>>=1;
}
return ans;
}
nod a,b;
int lowbit(int now)
{
return (now&(-now));
}
int countbit(int now)
{
int tot=0;
while(now)
now-=lowbit(now),tot++;
return tot;
}
int check[maxn];
ll cal(int now)
{
ll res=0;
for(int state=0;state<(1<<k);state++)
{
nod temp1=a,temp2=b;
for(int i=1;i<=n;i++)
{
check[i]=1;
for(int j=0;j<k;j++)
{
if((1<<j)&state)
{
if(i==pos[j])
check[i]=0;
}
}
}
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if ((!check[i])||(!check[j]))
{
temp1.a[i][j+n]=0;temp1.a[j][i+n]=0;
temp2.a[i+n][j]=0;temp2.a[j+n][i]=0;
temp2.a[i+n][j+n]=0;temp2.a[j+n][i+n]=0;
}
nod temp=mul(temp1,pow(temp2,now));
if(countbit(state)&1)
{
res-=temp.a[1][2];
res=((res%mod)+mod)%mod;
}
else
{
res+=temp.a[1][2];
res%=mod;
}
}
return res;
}
int main()
{
scanf("%d%d%d%d%d",&n,&m,&k,&l,&r);
b.n=b.m=2*n;a.n=n;a.m=2*n;
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
b.a[n+x][n+y]++; b.a[n+y][n+x]++;
b.a[n+x][y]++; b.a[n+y][x]++;
}
for(int i=1;i<=n;i++)
{
b.a[i][i]=1;
a.a[i][i]=1;
a.a[i][n+i]++;
}
for(int i=0;i<k;i++)
scanf("%d",&pos[i]);
ll ans=0;
ans+=cal(r);
if(l>=1) ans-=cal(l-1);
ans=((ans%mod)+mod)%mod;
printf("%lld\n",ans);
}