JZOJ 5398. 【NOIP2017提高A组模拟10.7】Adore
2017-10-07 21:02
344 查看
题目
Description小w 偶然间见到了一个DAG。
这个DAG 有m 层,第一层只有一个源点,最后一层只有一个汇点,剩下的每一层都有k 个节点。
现在小w 每次可以取反第i(1 < i < n - 1) 层和第i + 1 层之间的连边。也就是把原本从(i, k1) 连到(i + 1, k2) 的边,变成从(i, k2) 连到(i + 1, k1)。
请问他有多少种取反的方案,把从源点到汇点的路径数变成偶数条?
答案对998244353 取模。
Input
一行两个整数m, k。
接下来m - 1 行, 第一行和最后一行有k 个整数0 或1,剩下每行有k2 个整数0 或1,第(j- 1)* k + t 个整数表示(i, j) 到(i + 1, t)有没有边。
Output
一行一个整数表示答案。
Sample Input
5 3
1 0 1
0 1 0 1 1 0 0 0 1
0 1 1 1 0 0 0 1 1
0 1 1
Sample Output
4
Data Constraint
100% 的数据满足4 <= m <= 10^4, k <= 10。
题解
这道题很容易看错,是整行路径取反。我们发现这题的两个亮点。①k≤10,②奇偶性。
所以可以设装压DP。
设f[i][j]表示做到第i行,此层状态(即二进制第k位从源点走(i,k)的方案数的奇偶性)为j的方案数。
cnt[i]表示二进制i的1的个数的奇偶性。
我们知道了第i层不取反的走到下一层的点的对应的方案数的奇偶性。
a[i]表示此行第i个点能否走到下一行的点(不取反)。
b[i]表示此行第i个点能否走到下一行的点(取反)。
a0表示不取反,下一行的状态。(a1表取反)
那么f[i][a0]+=f[i][s],f[i][a1]+=f[i][s]。
a0=Σkj=1cnt[a[i]与s]∗2j−1
这表示什么意思?
如果第i+1行的某x个二进制位为1,说明到点(i+1,x)方案数为奇数。
走到(i,j)的方案数为奇数,且能够走到第i+1行的点(i+1,x),对走到(i+1,x)的方案数贡献为奇数。否则为偶数。
至于走到(i+1,x)的方案数则为上一行k个点走到(i+1,x)的方案数的总和。
所以二进制数a[i]&s的1的个数的奇偶性就代表走到(i+1,x)的方案数的奇偶性。
第1行和第n-1行要特殊一些,①不能将路径取反,②该行只有1个点。
第1行和第n-1行的转移与第2~n-2行类似。
总结一下
①虽然这是道很多人认为很简单的DP题,但我认为想起来不简单。
②值得推敲的:
每一行的取反/不取反可以通过DP的形式组成了一个个不重不漏的状态。
③即使我知道这是状压DP,但是算方案数的奇偶性还是挺恶心的一件事。
即运算/状态转移方面有很大的问题。
解决方案:利用二进制的巧妙性。
(I)条件的合并:逻辑运算。
(II)奇数偶数加起来的和的奇偶性&二进制数的1的个数的奇偶性相结合。
代码
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define N 10010 #define LL long long #define mo 998244353 #define fo(i,a,b) for(i=a;i<=b;i++) using namespace std; LL _2[15]; LL i,j,k,l,n,m,x,o,ans; LL s,a0,a1,a[15],b[15]; LL f [1030],cnt[1030]; int main(){ freopen("adore.in","r",stdin); freopen("adore.out","w",stdout); _2[1]=1;fo(i,2,14)_2[i]=(_2[i-1]*2)%mo; scanf("%lld%lld",&n,&k); s=0; fo(i,1,k){ scanf("%lld",&x); s|=x*_2[i]; } f[0][s]=1;o=0; fo(i,0,_2[k+1]-1)cnt[i]=cnt[i/2]^(i&1); fo(i,2,n-2){ o=1-o; memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); memset(f[o],0,sizeof(f[o])); fo(j,1,k)fo(l,1,k){ scanf("%lld",&x); if(x)a[j]|=_2[l],b[l]|=_2[j]; } fo(s,0,_2[k+1]-1) if(f[1-o][s]){ a0=a1=0; fo(j,1,k){ a0|=cnt[s&a[j]]*_2[j]; a1|=cnt[s&b[j]]*_2[j]; } f[o][a0]=(f[o][a0]+f[1-o][s])%mo; f[o][a1]=(f[o][a1]+f[1-o][s])%mo; } } o=1-o; memset(f[o],0,sizeof(f[o])); a[1]=0; fo(i,1,k){ scanf("%lld",&x); a[1]|=x*_2[i]; } fo(s,0,_2[k+1]-1) if(f[1-o][s]){ a0=cnt[s&a[1]]*_2[1]; f[o][a0]=(f[o][a0]+f[1-o][s])%mo; } printf("%lld",f[o][0]); return 0; }
相关文章推荐
- JZOJ5398. 【NOIP2017提高A组模拟10.7】Adore
- JZOJ 5398. 【NOIP2017提高A组模拟10.7】Adore
- JZOJ 5399. 【NOIP2017提高A组模拟10.7】Confess
- 【JZOJ 5400】【NOIP2017提高A组模拟10.7】Repulsed
- JZOJ 5400. 【NOIP2017提高A组模拟10.7】Repulsed
- JZOJ 5400. 【NOIP2017提高A组模拟10.7】Repulsed
- JZOJ5400. 【NOIP2017提高A组模拟10.7】Repulsed 树型DP+贪心
- jzoj5399 【NOIP2017提高A组模拟10.7】Confess
- JZOJ5400. 【NOIP2017提高A组模拟10.7】Repulsed
- jzoj5400. 【NOIP2017提高A组模拟10.7】Repulsed
- JZOJ5399. 【NOIP2017提高A组模拟10.7】Confess bitset
- jzoj5398. 【NOIP2017提高A组模拟10.7】Adore
- [JZOJ5394]【NOIP2017提高A组模拟10.5】Ping
- jzoj5336 【NOIP2017提高A组模拟8.24】提米树 (dfs序dp,奇异姿势dp)
- JZOJ100041. 【NOIP2017提高A组模拟7.12】列车调度
- JZOJ 100045. 【NOIP2017提高A组模拟7.13】好数
- JZOJ100043. 【NOIP2017提高A组模拟7.13】第K小数
- JZOJ 5404. 【NOIP2017提高A组模拟10.10】Graph
- 【JZOJ4932】【NOIP2017提高组模拟12.24】B
- JZOJ5358. 【NOIP2017提高A组模拟9.12】BBQ