[agc017F]Zigzag
来源:互联网 发布:ubuntu 字体 编辑:程序博客网 时间:2024/06/04 19:41
题目大意
有一个n行的三角形,第i行有i个格子。第i行第j个格子用(i,j)表示。从(i,j)可以到达(i+1,j)和(i+1,j+1)。现在要确定m条从(1,1)出发到第n行的路径。设第a条路径走到的第b个格子是(b,X[a,b]),对于任意a < b,不能存在i,使得X[a,i]>X[b,i]。同时还有K条形如(a,b,c)的限制,表示第a条路径第b个点到第b+1个点必须往方向c走。
求合法的方案数模
n,m≤20
分析
如果尝试直接表示某一行m条路径的状态,运行效率是很低的。
考虑到每一个点出发只有两个方向,那么可以用二进制数来表示一条路径(0表示往(i+1,j)走,1表示(i+1,j+1))。当确定第i条路径的时候,只要知道第i-1条路径就可以了。
假设正在确定第i条路径,并且路径前j-1位已经确定了,同时前j-1位还和第i-1条路径相同。设S表示第i-1条路径的状态。现在如果S的第j位为0,且第i条路径的第j位为1,那么第j位出现开始不同。接下来我们找到S在第j位之后的第一个1,把这个1变成0,并把第j位赋为1,即强行把第i-1条路径改成前j位与第i条一致,容易证明这是等价的。因为在这两位之间无论第i条路径怎么走都不会不合法。
如果找不到下一个1,那么第i条路径之后就可以随便走了。
根据上面的思路就可以DP了。时间复杂度
#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int N=20,M=524288,mo=1e9+7;typedef long long LL;int n,m,K,lim[N][N],g[M],f[2][M],p,q,nxt[N][M],h[N][M],ans,T;int main(){ scanf("%d%d%d",&n,&m,&K); T=1<<n-1; memset(lim,255,sizeof(lim)); for (int a,b;K--;scanf("%d",&lim[a-1][b-1])) scanf("%d%d",&a,&b); for (int i=1,j,k,la;i<M;i++) { for (j=T>>1,k=n-2,la=0;k>=0;k--,j>>=1) { nxt[k][i]=la; if (j&i) la=j; } } g[0]=1; for (int i=0,j,k,st;i<m;i++) { p=0; q=1; memcpy(f[0],g,sizeof(g)); memset(h,0,sizeof(h)); for (j=0,k=1;j<n-1;j++,p^=1,q^=1,k<<=1) { memset(f[q],0,sizeof(f[q])); for (st=0;st<T;st++) if (f[p][st]>0) { if (lim[i][j]==-1) { f[q][st]=(f[q][st]+f[p][st])%mo; if (!(k&st)) { if (!nxt[j][st]) h[j+1][st|k]=(h[j+1][st|k]+f[p][st])%mo; else f[q][(st|k)^nxt[j][st]]=(f[q][(st|k)^nxt[j][st]]+f[p][st])%mo; } }else if (lim[i][j]==0) { if ((k&st)) continue; f[q][st]=(f[q][st]+f[p][st])%mo; }else { if ((k&st)) { f[q][st]=(f[q][st]+f[p][st])%mo; }else { if (!nxt[j][st]) h[j+1][st|k]=(h[j+1][st|k]+f[p][st])%mo; else f[q][(st|k)^nxt[j][st]]=(f[q][(st|k)^nxt[j][st]]+f[p][st])%mo; } } } } for (j=2,k=2;j<n;j++,k<<=1) { for (st=0;st<k;st++) if (h[j-1][st]>0) { if (lim[i][j-1]!=1) h[j][st]=(h[j][st]+h[j-1][st])%mo; if (lim[i][j-1]!=0) h[j][st|k]=(h[j][st|k]+h[j-1][st])%mo; } } for (st=0;st<T;st++) g[st]=(f[p][st]+h[n-1][st])%mo; } ans=0; for (int st=0;st<T;st++) ans=(ans+g[st])%mo; printf("%d\n",ans); return 0;}
阅读全文
0 0
- [agc017f]Zigzag
- [agc017F]Zigzag
- zigzag
- zigzag
- ZigZag
- zigzag
- Zigzag
- ZigZag
- ZigZag
- ZigZag
- Zigzag
- ZigZag Conversion
- ZigZag Conversion
- ZigZag Conversion
- zigzag矩阵
- Zigzag Conversion
- zigzag数组
- zigzag数组
- CIDR与路由聚合
- 获得内核函数地址的四种方法
- IEnumerator 和IEnumerable区别
- 高效App框架设计与重构
- MySQL链接
- [agc017F]Zigzag
- Filter(第三节)
- python: reduce函数
- 列表表达式实例
- Action和Page数据共享方式 (值栈/Context) 值栈获取方式
- Search for a Range--LeetCode
- C++ 数论-质因数分解
- Struts 2 访问session request application 对象的方式
- Mapping the request body with the @RequestBody annotation