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
20% 的数据满足n <= 10, k <= 2
40% 的数据满足n <= 10^3, k <= 2。
60% 的数据满足m <= 10^3, k <= 5。
100% 的数据满足4 <= m <= 10^4, k <= 10。
题解
最终的答案只是与奇偶性有个,
那么就只保留它的奇偶性。
而且这里的k很小,就可以状态压缩。
设
转移的时候是整行转移。
code
#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#define ll long long
#define N 10003
#define db double
#define P putchar
#define G getchar
#define mo 998244353
using namespace std;
char ch;
void read(int &n)
{
n=0;
ch=G();
while((ch<'0' || ch>'9') && ch!='-')ch=G();
ll w=1;
if(ch=='-')w=-1,ch=G();
while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
n*=w;
}
ll max(ll a,ll b){return a>b?a:b;}
ll min(ll a,ll b){return a<b?a:b;}
ll abs(ll x){return x<0?-x:x;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}
int f[N][2048],n,m,k,t,z[13],g[13],w[13],ans,num[2048];
int main()
{
freopen("adore.in","r",stdin);
freopen("adore.out","w",stdout);
z[0]=1;for(int i=1;i<13;i++)z[i]=z[i-1]*2;
read(n);read(k);m=0;
for(int i=0;i<k;i++)
read(t),m|=z[i]*t;
f[1][m]=1;
for(int s=0;s<=z[k];s++)
num[s]=num[s>>1]^(s&1);
for(int i=1;i<n-2;i++)
{
memset(w,0,sizeof(w));
memset(g,0,sizeof(g));
for(int j=0;j<k;j++)
for(int p=0;p<k;p++)
{
read(t);
g[j]|=(t<<p);
w[p]|=(t<<j);
}
for(int s=0;s<z[k];s++)
if(f[i][s])
{
int s1=0,s2=0;
for(int j=0;j<k;j++)
s1|=(num[s&w[j]]<<j),s2|=(num[s&g[j]]<<j);
f[i+1][s1]=(f[i+1][s1]+f[i][s])%mo;
f[i+1][s2]=(f[i+1][s2]+f[i][s])%mo;
}
}
m=0;
for(int i=0;i<k;i++)
read(t),m|=t<<i;
ans=0;
for(int s=0;s<z[k];s++)
ans=(ans+(num[s&m]?0:f[n-2][s]))%mo;
write(ans);
}