[JZOJ5398]:Adore(状压DP+记忆化搜索)

题目描述

  小$w$偶然间见到了一个$DAG$。
  这个$DAG$有$m$层,第一层只有一个源点,最后一层只有一个汇点,剩下的每一层都有$k$个节点。
  现在小$w$每次可以取反第$i(1<i<n-1)$层和第$i+1$层之间的连边。也就是把原本从$(i,k_1)$连到$(i+1,k_2)$的边,变成从$(i,k_2)$连到$(i+1,k_1)$。
  请问他有多少种取反的方案,把从源点到汇点的路径数变成偶数条?
  答案对$998244353$取模。


输入格式

  一行两个整数$m,k$。
  接下来$m-1$行,第一行和最后一行有$k$个整数$0$或$1$,剩下每行有$k^2$个整数$0$或$1$,第$(j-1)\times k+t$个整数表示$(i,j)$到$(i+1,t)$有没有边。


输出格式

  一行一个整数表示答案。


样例

样例输入:

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

样例输出:

4


数据范围与提示

  $20\%$的数据满足$n\leqslant 10,k\leqslant 2$。
  $40\%$的数据满足$n\leqslant 10^3,k\leqslant 2$。
  $60\%$的数据满足$m\leqslant 10^3,k\leqslant 5$。
  $100\%$的数据满足$4\leqslant m\leqslant 10^4,k\leqslant 10$。


题解

发现$k$很小,考虑状压$DP$,设$dp[i][s]$表示第$i$行,能连边的点的状态为$s$的方案数。

转移用记忆化搜索即可,从后往前搜索。

时间复杂度:$\Theta(NK2^K)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
int M,K,S;
int Map[2][10001][11],a[11],g[1025];
long long dp[10001][1025];
int lowbit(int x){return x&-x;}
long long dfs(int x,int s)
{
	if(dp[x][s]!=-1)return dp[x][s];
	if(x==2)
	{
		dp[x][s]=1;
		for(int i=1;i<=K;i++)dp[x][s]^=a[i]&((s&(1<<(i-1)))!=0);
	}
	else
	{
		int ls=0,rs=0;
		for(int i=1;i<=K;i++)
		{
			ls|=g[Map[0][x-1][i]&s]<<(i-1);
			rs|=g[Map[1][x-1][i]&s]<<(i-1);
		}
		dp[x][s]=(dfs(x-1,ls)+dfs(x-1,rs))%mod;
	}
	return dp[x][s];
}
int main()
{
	memset(dp,-1,sizeof(dp));
	scanf("%d%d",&M,&K);
	for(int i=1;i<(1<<K);i++)g[i]=g[i-lowbit(i)]^1;
	for(int i=1;i<=K;i++)scanf("%d",&a[i]);
	for(int i=2;i<M-1;i++)
		for(int j=1;j<=K;j++)
			for(int k=1;k<=K;k++)
			{
				int x;scanf("%d",&x);
				Map[0][i][j]|=x<<(k-1);
				Map[1][i][k]|=x<<(j-1);
			}
	for(int i=1;i<=K;i++)
	{
		int x;
		scanf("%d",&x);
		S|=x<<(i-1);
	}
	printf("%lld",dfs(M-1,S));
	return 0;
}


rp++

原文地址:https://www.cnblogs.com/wzc521/p/11832842.html

时间: 2024-11-09 06:04:46

[JZOJ5398]:Adore(状压DP+记忆化搜索)的相关文章

UVA - 10817 Headmaster&#39;s Headache (状压dp+记忆化搜索)

题意:有M个已聘教师,N个候选老师,S个科目,已知每个老师的雇佣费和可教科目,已聘老师必须雇佣,要求每个科目至少两个老师教的情况下,最少的雇佣费用. 分析: 1.为让雇佣费尽可能少,雇佣的老师应教他所能教的所有科目. 2.已聘老师必须选,候选老师可选可不选. 3.dfs(cur, subject1, subject2)---求出在当前已选cur个老师,有一个老师教的科目状态为 subject1,有两个及以上老师教的科目状态为 subject2的情况下,最少的雇佣费用. dp[cur][subje

UVa 10817 (状压DP + 记忆化搜索) Headmaster&#39;s Headache

题意: 一共有s(s ≤ 8)门课程,有m个在职教师,n个求职教师. 每个教师有各自的工资要求,还有他能教授的课程,可以是一门或者多门. 要求在职教师不能辞退,问如何录用应聘者,才能使得每门课只少有两个老师教而且使得总工资最少. 分析: 因为s很小,所以可以用状态压缩. dp(i, s1, s2)表示考虑了前i个人,有一个人教的课程的集合为s1,至少有两个人教的集合为s2. 在递归的过程中,还有个参数s0,表示还没有人教的科目的集合. 其中m0, m1, s0, s1, s2的计算用到位运算,还

状压DP+记忆化搜索 UVA 1252 Twenty Questions

题目传送门 1 /* 2 题意:给出一系列的01字符串,问最少要问几个问题(列)能把它们区分出来 3 状态DP+记忆化搜索:dp[s1][s2]表示问题集合为s1.答案对错集合为s2时,还要问几次才能区分出来 4 若和答案(自己拟定)相差小于等于1时,证说明已经能区分了,回溯.否则还要加问题再询问 5 */ 6 /************************************************ 7 * Author :Running_Time 8 * Created Time :

UVa 1252 (状压DP + 记忆化搜索) Twenty Questions

题意: 有n个长为m的各不相同的二进制数(允许存在前导0),别人已经事先想好n个数中的一个数W,你要猜出这个数. 每次只可以询问该数的第K为是否为1. 问采用最优询问策略,则最少需要询问多少次能保证猜到. 比如有1100 和 0110两个数,只需要询问第一或第三位数是否为1,即可猜中,因此答案为1. 分析: d(s, a)表示已经询问了的集合s,在已经询问了的集合中W中为1的集合为a,还需要询问多少次. 如果下一次询问第k位,则询问次数为: 然后取所有k里的最小值即可. 预处理: 对于每个s和a

11782 - Optimal Cut(树形DP+记忆化搜索)

题目链接:11782 - Optimal Cut 题意:按前序遍历给定一棵满二叉树,现在有k次,可以选k个节点,获得他们的权值,有两个条件: 1.一个节点被选了,他的子节点就不能选了. 2.最终选完后,根到所有叶子的路径上,都要有一个被选的节点. 思路:树形dp,dp[u][k]代表在结点u,可以选k个节点,那么就分两种情况 选u节点,dp[u][k] = node[u]; 选子节点之和,那么就把k次分配给左右孩子,dp[u][k] = max(dp[u][k], dp[u][i], dp[u]

[hihocoder 1033]交错和 数位dp/记忆化搜索

#1033 : 交错和 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个数 x,设它十进制展从高位到低位上的数位依次是 a0,?a1,?...,?an?-?1,定义交错和函数: f(x)?=?a0?-?a1?+?a2?-?...?+?(?-?1)n?-?1an?-?1 例如: f(3214567)?=?3?-?2?+?1?-?4?+?5?-?6?+?7?=?4 给定 输入 输入数据仅一行包含三个整数,l,?r,?k(0?≤?l?≤?r?≤?1018,?|k|

poj1664 dp记忆化搜索

http://poj.org/problem?id=1664 Description 把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法. Input 第一行是测试数据的数目t(0 <= t <= 20).以下每行均包含二个整数M和N,以空格分开.1<=M,N<=10. Output 对输入的每组数据M和N,用一行输出相应的K. Sample Input 1 7 3 Sample Output 8 /

【DP】树形DP 记忆化搜索

DP中的树形DP,解决方法往往是记忆化搜索.显然,树上递推是很困难的.当然做得时候还是得把状态定义和转移方程写出来:dp[u][1/0]表示以u为根节点的树 涂(1) 或 不涂(0) 颜色的最少方案数.树上DP有两个经典问法:一条边两端至少有个一个端点涂色,问整个tree最少涂色次数:还有一种忘了...此题是前种问法. #include<cstdio> #include<cstring> #include<algorithm> using namespace std;

POJ 4968 DP||记忆化搜索

给出N个人的平局分X 根据GPA规则计算可能的最高平均GPA和最低平均GPA 可以DP预处理出来所有结果  或者记忆化搜索 DP: #include "stdio.h" #include "string.h" int inf=100000000; double a[11][1100],b[11][1100]; double Max(double a,double b) { if (a<b) return b; else return a; } double M