【ZJOI2005】沼泽鳄鱼

来源:互联网 发布:四川广电网络广安电话 编辑:程序博客网 时间:2024/04/27 15:47

题目

潘塔纳尔沼泽地号称世界上最大的一块湿地,它地位于巴西中部马托格罗索州的南部地区。每当雨季来临,这里碧波荡漾、生机盎然,引来不少游客。
  为了让游玩更有情趣,人们在池塘的中央建设了几座石墩和石桥,每座石桥连接着两座石墩,且每两座石墩之间至多只有一座石桥。这个景点造好之后一直没敢对外开放,原因是池塘里有不少危险的食人鱼。
  豆豆先生酷爱冒险,他一听说这个消息,立马赶到了池塘,想做第一个在桥上旅游的人。虽说豆豆爱冒险,但也不敢拿自己的性命开玩笑,于是他开始了仔细的实地勘察,并得到了一些惊人的结论:食人鱼的行进路线有周期性,这个周期只可能是2,3或者4个单位时间。每个单位时间里,食人鱼可以从一个石墩游到另一个石墩。每到一个石墩,如果上面有人它就会实施攻击,否则继续它的周期运动。如果没有到石墩,它是不会攻击人的。
  借助先进的仪器,豆豆很快就摸清了所有食人鱼的运动规律,他要开始设计自己的行动路线了。每个单位时间里,他只可以沿着石桥从一个石墩走到另一个石墩,而不可以停在某座石墩上不动,因为站着不动还会有其它危险。如果豆豆和某条食人鱼在同一时刻到达了某座石墩,就会遭到食人鱼的袭击,他当然不希望发生这样的事情。
  现在豆豆已经选好了两座石墩Start和End,他想从Start出发,经过K个单位时间后恰好站在石墩End上。假设石墩可以重复经过(包括Start和End),他想请你帮忙算算,这样的路线共有多少种(当然不能遭到食人鱼的攻击)。

【约定】
  1 ≤ N ≤ 50
  1 ≤ K ≤ 2,000,000,000
  1 ≤ NFish ≤ 20

分析

首先我们可以想出一个简单的dp方程,而k又那么大,于是我们想到可以用矩阵乘法优化。
于是我们会发现这样似乎有问题,因为我们不知道转移时是否合法(有食人鱼)
如何才能构造合理的矩阵呢?
然后我们可以发现循环很小,才2,3,4
这引导我们想最小公倍数!
对,那么我们可以把k分成k/lcm()份,每份快速幂一下就行了。
构造前lcm个时候合成的矩阵的时候,要乘上每一个时间的矩阵,设第i时刻的矩阵为ai,
则a[lcm]=a[1]*a[2]..a[lcm];
而每个时间的矩阵就是读入的矩阵,然后把当前有的食人鱼的位置赋为0,因为不可以转移。
然后就ans*ksm(a[lcm],K);//ans初始值:ans[1][st]=1;

#include<iostream>#include<cstdio>#include<cstdlib>#include<algorithm>#include<cmath>#include<cstring>using namespace std;const int N=55;typedef long long martix[N][N];const int mo=10000;martix b[13],c,d,an,a;int n,m,st,en,T,x,y,nn,p[25][8];int get(int x,int y){    if (x%y==0) return y;else return x%y;}void mul(martix a,const martix b){    martix c;    memset(c,0,sizeof(c));    for(int i=1;i<=n;i++)        for(int j=1;j<=n;j++)          for(int k=1;k<=n;k++)            c[i][j]=(c[i][j]+a[i][k]*b[k][j])%mo;    memcpy(a,c,sizeof (martix));}int main(){    scanf("%d%d%d%d%d",&n,&m,&st,&en,&T);    st++;en++;    for(int i=1;i<=m;i++){        scanf("%d%d",&x,&y);        x++;y++;        a[x][y]=a[y][x]=1;    }    scanf("%d",&nn);    int R[13];    memset(R,0,sizeof(R));    int lcm=1;    for(int i=1;i<=nn;i++){        scanf("%d",&p[i][0]);        for(int j=1;j<=p[i][0];j++) {            scanf("%d",&p[i][j]);p[i][j]++;        }        if (!R[p[i][0]]) lcm*=p[i][0];        R[p[i][0]]=1;    }    if (R[4]&&R[2]) lcm=lcm/2;    for(int i=1;i<=n;i++) c[i][i]=1;    for(int i=1;i<=lcm;i++){        memcpy(b[i],a,sizeof(a));        for(int j=1;j<=nn;j++) {            int op=p[j][get(i,p[j][0])];            for(int k=1;k<=n;k++) b[i][op][k]=0;        }        mul(c,b[i]);    }    int t=T/lcm;    for(int i=1;i<=n;i++) d[i][i]=1;    while (t){        if (t&1) mul(d,c);        mul(c,c);        t>>=1;    }    for(int i=1;i<=T%lcm;i++) mul(d,b[i]);    an[1][st]=1;    mul(an,d);    printf("%d",an[1][en]);}
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 临牌遗失了一张怎么办 临牌只有一张了怎么办 临时牌丢了一个怎么办 药流出血特别多怎么办 新车刮擦了一点怎么办 自己的车撞墙了怎么办 新车被撞了个坑怎么办 车门被刮变形了怎么办 撞到别人的新车怎么办 新车掉了一点漆怎么办 新车擦了点漆怎么办 车挂了一点漆怎么办 第一天上班中途想走了怎么办 车子前脸裂开了怎么办 不想干了想辞职怎么办 药流期间老是吐怎么办 在工厂上班辞工后没发工资怎么办 培训期三天想走怎么办 药流吃了药吐了怎么办 工作3天不下去怎么办 在新公司融不进去怎么办 药流吃药吐了怎么办 药流期间发烧了怎么办 药流时第一天出现呕吐怎么办有事吗 药流第一天忘记第二次吃药了怎么办 药流吃药后吐了怎么办 药流只排血块不见孕囊怎么办 药流三天还有血怎么办 药流15天同房了怎么办 药流22天同房了怎么办 药流一直不排出怎么办 宝宝脸过敏红了怎么办 小孩湿疹脸上都是红红的怎么办 眼周刺痛红红的怎么办 脸敷面膜刺痛红红的怎么办 脸上有凹凸不平的坑怎么办 宝宝脸上角质层薄有红血丝怎么办 红衣军到决赛圈怎么办 宝宝湿疹留下的黑印怎么办 出牙宝宝很烦躁怎么办 法斗嘴唇破了怎么办