题解 ABC025D【25個の整数】
*3006。
数据范围明示状压 DP,但是涉及到填数不好直接状压,因为我们对每个格子只能记录一个二进制位,不可能知道每个数都在什么位置。
不妨换个思路,不难想到一个二进制位可以用来记录这个位置是否已经填数,只需要利用上这个信息。注意到我们不关心具体填的数是多少,只关心偏序关系,因此可以从小到大填数。
从小到大填数时,不存在长度为 的单调数列等价于:填的位置左右填数状态相同,且上下填数状态相同(填数状态指是否已经填数)。可以根据这一点判断填数是否合法,并完成转移。
时间复杂度 ,其中 。
//By: OIer rui_er
#include <bits/stdc++.h>
#define rep(x,y,z) for(int x=(y);x<=(z);x++)
#define per(x,y,z) for(int x=(y);x>=(z);x--)
#define debug(format...) fprintf(stderr, format)
#define fileIO(s) do{freopen(s".in","r",stdin);freopen(s".out","w",stdout);}while(false)
using namespace std;
typedef long long ll;
mt19937 rnd(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()).count());
int randint(int L, int R) {
uniform_int_distribution<int> dist(L, R);
return dist(rnd);
}
template<typename T> void chkmin(T& x, T y) {if(x > y) x = y;}
template<typename T> void chkmax(T& x, T y) {if(x < y) x = y;}
const int mod = 1e9+7;
int a[25], pos[25], dp[1<<25];
void calc(int S, int k) {
int x = k / 5, y = k % 5;
if(0 < x && x < 4 && ((S >> (k - 5)) & 1) != ((S >> (k + 5)) & 1)) return;
if(0 < y && y < 4 && ((S >> (k - 1)) & 1) != ((S >> (k + 1)) & 1)) return;
dp[S] = (dp[S] + dp[S^(1<<k)]) % mod;
}
int main() {
memset(pos, -1, sizeof(pos));
rep(i, 0, 24) {
scanf("%d", &a[i]);
if(a[i]) pos[a[i]-1] = i;
}
dp[0] = 1;
rep(S, 1, (1<<25)-1) {
int u = __builtin_popcount(S) - 1;
if(pos[u] >= 0) calc(S, pos[u]);
else rep(i, 0, 24) if((S >> i) & 1) calc(S, i);
}
printf("%d\n", dp[(1<<25)-1]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
2022-03-22 题解洛谷 P2691【逃离】
2022-03-22 题解洛谷 P8216【[THUPC2022 初赛] 画图】