首页 > 其他分享 >luogu P1896 [SCOI2005] 互不侵犯 题解

luogu P1896 [SCOI2005] 互不侵犯 题解

时间:2024-07-28 13:06:15浏览次数:15  
标签:__ 状态 sta int 题解 sum P1896 ones luogu

luogu P1896 [SCOI2005] 互不侵犯 题解

题目传送门

思路

状态压缩 dp 。

状态压缩 dp

对于每一行,用一个 \(n\) 位二进制数表示每行的状态,则对于上下两行之间,设上行的数字为 \(a\) ,下行的数字为 \(b\) ,状态不合法有三种情况:

  1. \(a \operatorname{and} b \neq 0\) ,即存在上行与下行同一列都有国王。
  2. \((a << 1) \operatorname{and} b \neq 0\) ,即上行存在国王在下行国王右上方。
  3. \(a \operatorname{and} (b << 1) \neq 0\) ,即上行存在国王在下行国王左上方。

定义数组 \(f_{i,j,k}\) 表示第 \(i\) 行的状态为 \(j\) 时已经有 \(k\) 个国王时的方案数, 集合 \(S\) 表示对于下行上行合法的状态的集合, \(ones_i\) 表示 \(i\) 在二进制下有多少位 \(1\)。

易推出状态转移方程式 : \(f_{i, j, k} = \sum_l^{l \in S} f_{i - 1, l, k - ones_j}\) 。

对于每一行 \(i\) ,暴力枚举上下两行的所有状态即可。

细节

代码中的 \(j\) 并不是真正的状态,而是该状态对应的编号。

代码

时间复杂度 \(O(n\times2^{20})\)

#include <iostream>
#include <cstdio>
typedef long long LL;

using namespace std;

#define LF(i, __l, __r) for (int i = __l; i <= __r; i++)
#define RF(i, __r, __l) for (int i = __r; i >= __l; i--)

const int N = 600, M = 12, K = 105;

int n, k, cnt;
int st[N], ones[N];
LL f[M][N][K], ans;

void Init(int u, int sum, int sta) {
    if (u >= n) {
        st[++cnt] = sta;
        ones[cnt] = sum;
        return;
    }

    Init(u + 1, sum, sta);
    Init(u + 2, sum + 1, sta | (1 << u));
}

int main() {
    scanf("%d%d", &n, &k);
    Init(0, 0, 0);

    LF(i, 1, cnt) f[1][i][ones[i]] = 1;

    LF(i, 2, n) LF(j, 1, cnt) LF(l, 1, cnt) {
        if (st[j] & st[l]) continue;
        if ((st[j] << 1) & st[l]) continue;
        if (st[j] & (st[l] << 1)) continue;
        RF(s, k, ones[j]) f[i][j][s] += f[i - 1][l][s - ones[j]];
    }

    LF(i, 1, cnt) ans += f[n][i][k];
    printf("%lld", ans);
    return 0;
}

子曰:“非其鬼而祭之,谄也。见义不为,无勇也。”

标签:__,状态,sta,int,题解,sum,P1896,ones,luogu
From: https://www.cnblogs.com/faruzan/p/18328111

相关文章

  • 洛谷P2440 题解
    P2440题解题目传送门提取关键词,题目需要的是数量大于$k$的最大$l$,考虑二分答案。可以二分枚举$l$的值,check函数中检验切割出该长度小段木头的个数,与$k$进行比较。小数据模拟例如,我们有五根木棍且$k=4$,分别为374106第一次循环$l=0,r=9,mid=4$。check函数中得到......
  • luogu P1896 [SCOI2005] 互不侵犯 题解
    luoguP1896[SCOI2005]互不侵犯题解题目传送门思路状态压缩dp。状态压缩dp对于每一行,用一个\(n\)位二进制数表示每行的状态,则对于上下两行之间,设上行的数字为\(a\),下行的数字为\(b\),状态不合法有三种情况:\(a\operatorname{and}b\neq0\),即存在上行与下行同......
  • Codeforces Round 962 (Div. 3) A - D详细题解(思路加代码Python,C++(垃圾灰名小白想
             吐槽一下,这次比赛不知道怎么的,可能是div3参加的人比较多吗,代码题解上去后全是inqueue,比赛的过程中我还看了提交的,80多页几千个提交全是inqueue,我的代码等了**半个多小时才运行,然后发现timelimit真的有点搞心态,思路在下一题我还要反过来去优化上一题,不过......
  • 逆序对的数量 - 题解
    逆序对的数量时间限制:C/C++1000MS,其他语言2000MS内存限制:C/C++64MB,其他语言128MB描述给定一个长度为\(n\)的整数数列,请你计算数列中的逆序对的数量。逆序对的定义如下:对于数列的第\(i\)个和第\(j\)个元素,如果满足\(i<j\)且\(a[i]>a[j]\),则其为一个逆序对;否则......
  • ABC364题解(D-G)
    D先对\(a\)从小到大排序。将题目转化成找到最小的\(d\),使得恰好有\(k\)个\(a_i\in[b-d,b+d]\)。对于每个询问\(b,k\),考虑二分答案。设待检查的答案为\(d\),二分找到最小的\(p1\)使得\(a_{p1}\geqb-d\)和最小的\(p2\)使得\(a_{p2}>b+d\),包含的数的个数即为\(......
  • 题解:P10481 Sudoku
    Sudoku来自蓝书思路优化搜索顺序,位运算常数优化。优化搜索顺序数独问题的搜索很简单,“搜索状态”就是每个位置上填了什么数。在每个状态下,选择一个未填位置,检查那些填入仍能满足数独条件(合法)的数字。构成的新的局面即为该状态的“分支”。足够暴力的写法为依次对每个位置进......
  • 2023CSP-j复赛题解
    csp-j题解update:2024.6.18-2024.6.25:重构题解第一题:小苹果原题洛谷P9748思路n表示当前长度求几天取完:每天取走\((n-1)/3+1\)个苹果,记录几天取完第\(n\)个苹果第几天被取走:当\(n\bmod3=0\)时被取走时间复杂度约为\(O(\log_n)\)#include<iostream>......
  • [ARC105C] Camels and Bridge 题解
    [ARC105C]CamelsandBridge题解出自梦熊比赛后,梦熊比赛出原题了,忘周知。也许更好的阅读体验思路全排列,差分约束,二分。全排列\(n\leq8\),且要指定顺序,易想到用全排列枚举所有状态。差分约束在全排列之后,需要求得每种状态的最短距离。定义所有骆驼的编号的集合为\(S\)......
  • ABC 364 F - Range Connect MST 题解
    一副扑克牌,去掉1到K,剩下就是我,赛后十秒过,我是joker。......
  • CF613E Puzzle Lover 题解
    Description给定一个\(2\timesn\)的矩阵,每个位置上有一个小写字母。有一个长度为\(k\)的小写字符串\(w\),询问矩阵中有多少条有向路径满足以下条件:路径上的字母连起来恰好为\(w\)。不多次经过同一个位置。只能向上下左右四个方向走。\(n,k\le2\times10^3\),答案......