首页 > 其他分享 >状压 DP 做题记录

状压 DP 做题记录

时间:2024-11-14 21:59:41浏览次数:1  
标签:const 记录 int rep 状压 st ------------ fst DP

1.普通状态压缩 DP

I.P1896 [SCOI2005] 互不侵犯

\(f_{i,j,st}\) 表示前 \(i\) 行中放置了 \(j\) 个国王,当前行状态为 \(st\) 的方案数。可以预处理出合法的状态与其 popcount,转移时枚举当前行状态和上一行状态,合法就转移。

const int N = 20,inf = 1e9,mod = 998244353;
const ll inff = 1e18;
int n,k,f[N][110][1000];
vector<int> v; int pcnt[1000];

il void solve() {
    //------------code------------
    read(n,k);
    rep(st,0,(1 << n) - 1) if (!((st << 1) & st) && !((st >> 1) & st)) 
        v.pb(st),pcnt[st] = __builtin_popcount(st);
    f[0][0][0] = 1;
    rep(i,1,n) for (auto st : v) for (auto stt : v)
        if (!(stt & st) && !((stt << 1) & st) && !((stt >> 1) & st)) {
            rep1(j,k,pcnt[st]) f[i][j][st] += f[i - 1][j - pcnt[st]][stt];
        }
    int ans = 0;
    for (auto st : v) ans += f[n][k][st];
    write(ans,'\n');
    // cerr << "Time : " << (db)(end - start) / CLOCKS_PER_SEC << " s" << endl;
    return ;
}

II.P2704 [NOI2001] 炮兵阵地

考虑将一行某个位置能否部署状压成一个二进制数,然后判断状态合法时可以直接把它们按位与起来。\(f_{i,st,st'}\) 表示前 \(i\) 行中,当前行状态为 \(st\),上一行状态为 \(st'\),最多能摆放的炮兵部队的数量。压掉一维就能过。

const int N = 110,inf = 1e9,mod = 998244353;
const ull base = 131,base_ = 233;
const ll inff = 1e18;
int n,m,a[N];
int f[3][1034][1034];
vector<PII> v;

il void solve() {
    //------------code------------
    read(n,m);
    rep(i,1,n) {
        string s; cin >> s;
        rep(j,0,m - 1) a[i] += (s[j] == 'H') * (1 << (m - 1 - j));
    }
    rep(st,0,(1 << m) - 1) if (!(st & (st >> 1)) && !(st & (st >> 2))) v.pb(st,__builtin_popcount(st));
    memset(f,-0x3f,sizeof f);
    for (auto x : v) f[1][x.fst][0] = x.snd;
    rep(i,2,n)
        for (auto st : v) if (!(st.fst & a[i]))
            for (auto stt : v) if (!(st.fst & stt.fst) && !(stt.fst & a[i - 1]))
                for (auto sttt : v) if (!(st.fst & sttt.fst) && !(stt.fst & sttt.fst) && !(sttt.fst & a[i - 2]))
                    chmax(f[i % 3][st.fst][stt.fst],f[(i - 1) % 3][stt.fst][sttt.fst] + st.snd);
    int ret = 0;
    for (auto st : v) if (!(st.fst & a[n]))
        for (auto stt : v) if (!(st.fst & stt.fst) && !(stt.fst & a[n - 1]))
            chmax(ret,f[n % 3][st.fst][stt.fst]);
    write(ret,'\n');
    return ;
}

III.P1879 [USACO06NOV] Corn Fields G

板子。\(f_{i,st}\) 表示前 \(i\) 行中当前行状态为 \(st\) 的种植方案数。

const int N = 22,inf = 1e9,mod = 1e8;
const ull base = 131,base_ = 233;
const ll inff = 1e18;
int n,m,a[N]; ll f[N][4100];
vector<int> v;

il void solve() {
    //------------code------------
    read(n,m);
    rep(i,1,n)
        rep(j,1,m) {
            int x; read(x);
            a[i] += (1 << (m - j)) * (!x);
        }
    rep(st,0,(1 << m) - 1) if (!(st & (st << 1))) v.pb(st);
    f[0][0] = 1;
    rep(i,1,n)
        for (auto st : v) if (!(st & a[i]))
            for (auto stt : v) if (!(st & stt) && !(stt & a[i - 1]))
                f[i][st] = (f[i][st] + f[i - 1][stt]) % mod;
    ll ans = 0;
    for (auto st : v) ans = (ans + f[n][st]) % mod;
    write(ans,'\n');
    return ;
}

IV.P3052 [USACO12MAR] Cows in a Skyscraper G

\(f_{st}\) 表示当前已将哪些物品进行分组,最小的分组数量。维护一个当前 \(f_{st}\) 的最大剩余体积,每次能放下就放,放不下就增加组数,同时更新最大剩余体积。

const int N = 3e5 + 10,inf = 1e9,mod = 998244353;
const ull base = 131,base_ = 233;
const ll inff = 1e18;
int n,m,w[20]; PII f[N];

il void solve() {
    //------------code------------
    read(n,m);
    rep(i,1,n) read(w[i]);
    rep(st,1,(1 << n) - 1) f[st] = {-inf,inf};
    f[0] = {m,1};
    rep(st,1,(1 << n) - 1)
        rep(i,0,n - 1) if (st >> i & 1) {
            if (f[st].snd >= f[st ^ (1 << i)].snd && f[st ^ (1 << i)].fst >= w[i + 1]) {
                chmax(f[st].fst,f[st ^ (1 << i)].fst - w[i + 1]);
                f[st].snd = f[st ^ (1 << i)].snd;
            } else if (f[st].snd >= f[st ^ (1 << i)].snd + 1 && f[st ^ (1 << i)].fst < w[i + 1]) {
                chmax(f[st].fst,m - w[i + 1]);
                f[st].snd = f[st ^ (1 << i)].snd + 1;
            }
            // cerr << st << " " << i << " " << f[st].snd << '\n';
        }
    write(f[(1 << n) - 1].snd,'\n');
    return ;
}

V.P2396 yyy loves Maths VII

显然有 \(\mathcal{O(2^n n)}\) 的做法,但是 1 s 可能跑不过,考虑优化 \(n\) 的那一维,每次取出状态的 lowbit 来进行转移,并减掉它,这样可以减少大量无用的判断,能过此题。最慢的点跑了有 600 ms

const int N = 2e7 + 10,inf = 1e9,mod = 1e9 + 7;
const ull base = 131,base_ = 233;
const ll inff = 1e18;
int n,m,a[N],b[3],f[N],g[N];

il int lowbit(int x) { return x & -x; }

il void solve() {
    //------------code------------
    read(n); rep(i,1,n) read(a[(1 << i - 1)]);
    read(m); rep(i,1,m) read(b[i]);
    f[0] = 1;
    rep(st,1,(1 << n) - 1) {
        g[st] = g[st ^ lowbit(st)] + a[lowbit(st)];
        bool fl = 1;
        rep(i,1,m) if (g[st] == b[i]) { fl = 0; break; }
        if (!fl) continue;
        int x = st;
        for (; x; x -= x & -x) f[st] = (f[st] + f[st ^ lowbit(x)]) % mod;
    }
    write(f[(1 << n) - 1],'\n');
    return ;
}

VI.P2831 [NOIP2016 提高组] 愤怒的小鸟

可以发现两个点可以唯一确定一条抛物线,预处理 \(sta_{i,j}\) 表示第 \(i\) 个点和第 \(j\) 个点组成的抛物线经过的点,对其做状压处理。现在就有一个 \(\mathcal{O(T2^n n^2)}\) 的做法,对于当前状态枚举接下来打哪条抛物线。这样并不能通过所有测试点,考虑优化。发现最终需要的答案是 \(f_{2^n - 1}\),其余有 \(f\) 对最终答案并没有贡献,那么它是无用的,显然我们最终状态 \(2^n - 1\) 在二进制下是有 \(n\) 个 1 的,那么每次对于当前状态要推到最终状态,二进制下第一个为 0 的位置到最后一定会被转移掉,变为 1,那么我们就可以找到这个位置,再枚举它和其它的点的抛物线,用此抛物线的 \(sta\) 来转移就足矣。最后时间复杂度是 \(\mathcal{O(T2^n n)}\) 的。

const int N = 270010,inf = 1e9,mod = 998244353;
const ull base = 131,base_ = 233;
const db eps = 1e-8;
const ll inff = 1e18;
int n,m; pair<db,db> a[N];
int cnt[20][20],f[N];

il void solve() {
    //------------code------------
    read(n,m);
    rep(i,1,n) cin >> a[i].fst >> a[i].snd;
    rep(i,1,n) rep(j,i + 1,n) {
        db x = a[i].fst,y = a[i].snd;
        db xx = a[j].fst,yy = a[j].snd;
        if (fabs(x - xx) < eps) { cnt[i][j] = cnt[j][i] = 0; continue; }
        db A = (y / x - yy / xx) / (x - xx),B = y / x - x * A;
        // cerr << i << " " << j << " " << A << " " << B << '\n';
        if (A >= 0) { cnt[i][j] = cnt[j][i] = 0; continue; }
        cnt[i][j] = 0;
        rep(k,1,n) if (fabs(A * a[k].fst * a[k].fst + B * a[k].fst - a[k].snd) < eps)
            cnt[i][j] += (1 << k - 1);
        cnt[j][i] = cnt[i][j];
    }
    rep(st,0,(1 << n) - 1) f[st] = inf;
    f[0] = 0;
    rep(st,0,(1 << n) - 2) {
        int p = -1;
        rep(i,0,n - 1) if (!(st >> i & 1)) { p = i; break; }
        chmin(f[st | (1 << p)],f[st] + 1);
        rep(i,1,n) if (i != p && ~cnt[p + 1][i]) chmin(f[st | cnt[p + 1][i]],f[st] + 1);
    }
    write(f[(1 << n) - 1],'\n');
    return ;
}

VII.P2473 [SCOI2008] 奖励关

显然有 \(f_{i,st}\) 表示前 \(i\) 次中,吃过的宝物的集合为 \(st\) 的最大期望分值。然后你会发现对于 \(f_i\),有一些状态是明显不合法的,此题起点唯一,但终点不唯一且有一些状态不可达的情况,所以需要倒推。

const int N = 20,inf = 1e9,mod = 998244353;
const ull base = 131,base_ = 233;
const ll inff = 1e18;
int k,n,s[N],p[N];
db f[110][32770];

il void solve() {
    //------------code------------
    read(k,n);
    rep(i,1,n) {
        read(p[i]); s[i] = 0;
        int x; read(x);
        while (x) {
            s[i] |= (1 << x - 1);
            read(x);
        }
    }
    f[k + 1][(1 << n) - 1] = 0;
    rep1(i,k,1)
        rep(st,0,(1 << n) - 1) {
            // cerr << i << " " << st << '\n';
            rep(j,1,n) 
                if ((st & s[j]) == s[j]) f[i][st] += max((f[i + 1][st | (1 << j - 1)] + p[j] * 1.0),f[i + 1][st]) / (db)n;
                else f[i][st] += f[i + 1][st] / (db)n;
        }
    db ans = f[1][0];
    printf("%.6lf\n",ans);
    return ;
}

等待更新。

标签:const,记录,int,rep,状压,st,------------,fst,DP
From: https://www.cnblogs.com/songszh/p/18540585/StateCompressionDP

相关文章

  • TCP_UDP
    TCP,UDPFlood攻击原理TCPFlood攻击配置环境WindowsServer2016配置服务器管理器,创建一个Web服务器并开启该服务器功能kali配置vim/etc/network/interfacesifupeth0开启网络查看Kaliip信息:修改路由器信息:拓扑关系如下所示:GNS3中修改路由器R......
  • Vue学习记录04
    计算属性模板中的表达式虽然方便,但也只能用来做简单的操作。如果在模板中写太多逻辑,会让模板变得臃肿,难以维护。比如说,我们有这样一个包含嵌套数组的对象:constauthor=reactive({name:'JohnDoe',books:['Vue2-AdvancedGuide','Vue3-BasicGuide'......
  • 基于UDP的tftp传输服务的客户端
    效果图下载上传:代码:#include<stdio.h>#include<sys/types.h>#include<sys/socket.h>#include<arpa/inet.h>#include<string.h>#include<unistd.h>#include<netinet/in.h>#include<stdlib.h>#include<......
  • java学习记录06
    正则表达式匹配规则对于正则表达式来说,它只能精确匹配字符串。例如:正则表达式“abc",只能匹配”abc",不能匹配“ab","Abc","abcd"等其他字符串。如果想匹配非ASCII字符,例如中文,那么就用\u####的十六进制表示,例如:a\u548cc匹配的是字符串"a和c",中文字符和的Unicode编码是548c......
  • java学习记录05
    Object类通用方法Object类是所有类的超类。如果在类声明中没有使用extends关键字明确指定超类,那么默认的超类就是Object类。这就意味着所有的对象(包括数组)都实现了该类的方法。Object的所有方法native表示这个方法的实现是由其他语言(例如C或C++)编写的,它并不在Java源代码中......
  • Vue学习记录03
    响应式基础声明响应式状态ref()在组合式API中,推荐使用ref()函数来声明响应式状态:import{ref}from'vue'constcount=ref(0)ref()接收参数,并将其包裹在一个带有.value属性的ref对象中返回:constcount=ref(0)console.log(count)//{value:0}console.log(......
  • cxGrid【过滤、排序】后获取选中记录的值和cxGrid空表判断
    方法一:使用函数GetRowValue此方法在表格过滤、排序后也正常,请注意:此代码顺序需要CXGRID的列顺序和ADOQUERY中SELECT的字段顺序一致,否则会取错。procedureTfrmBillExtraction.pmGetBill_D_DatasClick(Sender:TObject);varI,J:Integer;beginwithcxGDBTV_Bill_M.Data......
  • stringRedisTemplate 异步操作的问题记录
    一、问题背景StringRedisTemplate使用stringRedisTemplate.opsForValue().set时,会出现set之后立马get获取值,发现获取不到set进去的值。二、问题原因1、在使用redisson的情况下,stringRedisTemplate.opsForValue().set操作会是异步操作,造成。你在set之后,立马get获取值的时候会......
  • GDPC-CSACTF Round2 WP Web篇
    先从简单的开始ezupload题目都把解题方法拍脸上了,随便上网找一个php一句话木马上传后拿webshell软件(我用的是蚁剑antsword)脸上就可以翻服务器了,最后在usr找到flag,比较搞笑的是我第一次出了点问题还以为要提权,经典把题目做难ezcmd同样是几乎送分题,跟一轮一样直接把PHP源码扔......
  • UNR #8 Day2 难度查找 个人记录
    个人记录,可能存在一些错误或者问题。好题。这题和元旦激光炮有一点像,都是考虑根据给定的矩阵大小关系,在不确定某个位置具体值的情况下,把一定大于/小于答案的位置挖掉。但是本题可以说是拓展了,因为它在确定的时候也递归成了一个子问题。我们要找某个\(n\timesm\)矩阵(满足从......