CodeForces 852B Neural Network country(dp+矩阵快速优化)

来源:互联网 发布:参与网络棋牌赌博 编辑:程序博客网 时间:2024/05/29 16:22

Neural Network country

time limit per test:2 seconds

memory limit per test:256 megabytes

input:standard input

output:standard output

Due to the recent popularity of the Deep learning new countries are starting to look like Neural Networks. That is, the countries are being built deep with many layers, each layer possibly having many cities. They also have one entry, and one exit point.

There are exactly L layers, each havingN cities. Let us look at the two adjacent layersL1 andL2. Each city from the layerL1 is connected to each city from the layerL2 with the traveling costcij for, and each pair of adjacent layers has the same cost in between their cities as any other pair (they just stacked the same layers, as usual). Also, the traveling costs to each city from the layerL2 are same for all cities in theL1, that iscij is the same for, and fixedj.

Doctor G. needs to speed up his computations for this country so he asks you to find the number of paths he can take from entry to exit point such that his traveling cost is divisible by given numberM.

Input

The first line of input contains N (1 ≤ N ≤ 106),L (2 ≤ L ≤ 105) andM (2 ≤ M ≤ 100), the number of cities in each layer, the number of layers and the number that travelling cost should be divisible by, respectively.

Second, third and fourth line contain N integers each denoting costs0 ≤ cost ≤ M from entry point to the first layer, costs between adjacent layers as described above, and costs from the last layer to the exit point.

Output

Output a single integer, the number of paths Doctor G. can take which have total cost divisible byM, modulo 109 + 7.

Example
Input
2 3 134 62 13 4
Output
2

Note

This is a country with 3 layers, each layer having2 cities. Paths , and are the only paths having total cost divisible by13. Notice that input edges for layer cities have the same cost, and that they are same for all layers.



        好久没有遇到这么单纯的矩阵快速幂的题目。

        大致题意就是,给你一个网络,这个网络分层,除了源汇直接相连的点以外,其余所有的层都是相同的。然后问你,从源点出发到汇点,路径权值和为某个特定的数字M的倍数的方案有多少种。

        事实证明,题目的数据范围确实是一个突破口。本题给出M的范围是100,可以说就是突破口。经过长期的做题,很容易知道这里直接用当前花费在M下的剩余系来表示状态即可,然后可以有前一层的状态转移到后一层。在不考虑层数和每一层点数的限制下,我们可以有如下状态转移方程dp[i][j]=Σdp[i-1][(j-a[i])%M]相当于表示从前一层的(j-a[i])%M花费转移到当前层的j花费。那么接下来,我们就考虑如何优化这个dp。可以看出这个dp具有矩阵乘法的形式,或者说,对于每转移,(j-a[i])%M到j,我可以看作有一条边从(j-a[i])%M连到j,那么问题就是求最后从源点到汇点的路径条数。因此,显然可以用矩阵快速优化。对于一条转移,我对应一条边,在邻接矩阵中表示边的条数。中间有L层,那么相应的相当于要在中间走L-1次,因此中间部分就是邻接矩阵的L-1次方。

        接着我们看看如何处理开始和结束。显然,开始的时候费用是0,所以说,对于源点连出去的边,我们对应是从花费0连边到相应路径的花费。然后这个邻接矩阵左乘中间部分的快速幂之后的邻接矩阵就是从源点到最后一层的花费对应的方案数。接着就是汇点了,一开始我的想法是和源点做同样的处理,即最后花费要为0,然后从相应路径花费连边到0,最后右乘之前的结果即可。但是你会发现连样例都过不了,为什么呢?因为注意到我们最后一层是点到点的连边,而不是费用到费用的连边。打个比方说,假设现在有一条费用为3、从最后一层的第一个点连到汇点的边,然后最后要求是13的倍数,如果这么做应该连边10->0,但是到最后一层费用为0的方案有多种,并不能保证每一种方案在最后一层的时候恰好在第一个点,如果不在,那么实际上是不能直接转移过去的,所以这么做会多算。

        所以说,为了解决这个问题,我们选择在中间计算的时候少计算一层,即把倒数第二层到最后一层的转移提出来,先不算,然后把这一层的转移与从最后一层到汇点的转移合并为新的一个邻接矩阵,最后再右乘即可。这样做相当于把最后一层的费用和到汇点的费用绑在了一起,就不会出现刚刚的错误。这题还是不简单的,具体见代码:

#include<bits/stdc++.h>#define mod 1000000007#define LL long long#define M 1000010#define N 100using namespace std;struct matrix{LL a[N][N];void init(){memset(a,0,sizeof(a));}friend matrix operator *(matrix x,matrix y)    {        matrix ans; ans.init();        for(int i=0;i<N;i++)            for(int j=0;j<N;j++)            {                for(int k=0;k<N;k++)                    ans.a[i][j]+=(x.a[i][k]*y.a[k][j])%mod;                ans.a[i][j]%=mod;            }        return ans;    }    friend matrix operator ^(matrix x,LL y)    {        matrix ans;        if (y==0)        {            memset(ans.a,0,sizeof(ans.a));            for(int i=0;i<N;i++) ans.a[i][i]=1;            return ans;        } else while ((y&1)==0) y>>=1,x=x*x;        ans=x; y>>=1;        for(;y!=0;y>>=1)        {            x=x*x; if ((y&1)!=0) ans=ans*x;        }        return ans;    }} x;int n,m,Mod,a[M];int main(){    x.init();    matrix h,t;//head和tail,表示首尾    h.init(); t.init();    scanf("%d%d%d",&n,&m,&Mod);    for(int i=1;i<=n;i++)    {        int v; scanf("%d",&v);        h.a[0][v%Mod]++;//源点连出的边,直接从0连到相应的费用    }    for(int i=1;i<=n;i++)    {        int v; scanf("%d",&v); a[i]=v;        for(int j=0;j<Mod;j++)//中间点,可以从任意费用转移            x.a[j][(j+v)%Mod]++;    }    matrix ans=h*(x^(m-2));//注意少弄一层,最后一层和到汇点的合并    for(int i=1;i<=n;i++)    {        int v; scanf("%d",&v);        t.a[(Mod-(v+a[i])%Mod)%Mod][0]++;//进行合并,构造新矩阵    }    ans=ans*t;//右乘求出结果    printf("%I64d\n",ans.a[0][0]);}

阅读全文
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 宝宝11个多月突然排斥妈妈怎么办 5个月婴儿粘妈妈怎么办 3岁宝宝记不住颜色怎么办 3岁宝宝不认字怎么办 墙纸被宝宝弄上各种颜色怎么办 三周半的孩子不认识数字怎么办 3岁幼儿不会数数怎么办 四岁宝宝不认识数字怎么办 三岁宝宝不认识数字怎么办 4岁半了不认识数字怎么办 5岁小朋友数字不认识怎么办 孩子读一年级字都不识几个怎么办 宝宝二周多了不分颜色怎么办 4岁儿童手指脱皮怎么办 孩子老是不会写2怎么办 宝宝胃浅容易吐怎么办 农村户口小孩去城里读书怎么办 小孩从城市回农村读书怎么办 天冷了怎么办教案反思 小孩上幼儿园不爱学习怎么办 曰光灯管监控要反光怎么办 立邦乳胶漆墙面脏了怎么办 橱柜门黑色边颜色花了怎么办 地板上有真实漆怎么办 吸了泡泡球的气怎么办 办公室上班坐着太累怎么办 金雀盆景生虫怎么办 租的房子墙脏怎么办 租住个厕所对着卧室怎么办 农村的房子没有房产证怎么办 墙面漆颜色深了怎么办 浴室门对卧室门怎么办 卧室40多个平方太大怎么办 卧室门洞太窄了怎么办 刷漆的墙面脏了怎么办 卧室颜色刷重了怎么办 感觉房子买小了怎么办 淋浴房一边是窗怎么办 1岁宝宝让狗咬了怎么办 2岁宝宝让狗咬了怎么办 带4个小孩只买两张儿童票怎么办