当前位置: 首页 > news >正文

赛前训练6 状压

A

简单树上差分.

B

维护 \(d_{i,j}\) 表示人 \(i\) 在第 \(j\) 位与哪些人有区别.预处理即可.

对于每个人,枚举提问的二进制状态;对于提问的每个二进制位,将它们的 \(d\) 全部拼起来,若能拼成 ((1<<n)-1)^(1<<i),则产生 \(c(j)\) 的贡献,其中 \(c(x)\) 代表 \(x\) 在二进制下 \(1\) 的个数, \(j\) 表示当前提问状态.

实现
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
//#define int long long
using namespace std;const int N=25;
int n,m;
int a[N][N],diff[N][N];signed main(){ios::sync_with_stdio(0);cin.tie(0);cin>>n>>m;for(int i=0;i<n;i++)for(int j=0;j<m;j++)cin>>a[i][j];for(int i=0;i<n;i++)for(int j=0;j<n;j++)for(int k=0;k<m;k++)if(a[i][k]!=a[j][k])diff[i][k]|=(1<<j);for(int i=0;i<n;i++){int ans=1e9;for(int j=0;j<(1<<m);j++){int cnt=0,person=0;for(int k=0;k<m;k++)if((j>>k)&1)person|=diff[i][k],cnt++;//cout<<person<<'\n';if((person|(1<<i))==(1<<n)-1)ans=min(ans,cnt);}cout<<(ans==1e9?-1:ans)<<' ';}return 0;
}

C

\(n \le 16\),直接状压 dp.

\(dp_i\) 表示字符串选取情况为 \(i\) 时的 trie 树节点最小值.

初始 \(dp_{1<<i}=|s_i|\),答案 \(dp_{(1<<n)-1}\).

转移考虑两棵 trie 树合并成 \(i\),易得 \(dp_i=dp_j+dp_{i \oplus j}-len(i)\).其中 \(len(i)\) 表示 \(i\) 状态下的 LCP.

这东西如何维护?我们发现,一堆字符串重排之后的 LCP,是由它们每种字母的最小出现次数决定的.于是可以维护 \(lcp(i,j)\) 表示 \(i\) 状态下字母 \(j\) 的最小出现次数.要维护 \(lcp(i,j)\),则必然还需要维护 \(cnt(i,j)\) 表示 \(s_i\) 中字母 \(j\) 的出现次数.这样,统计出 \(cnt\) 后,\(lcp\) 只需要枚举状态然后对它们取 \(\min\),而 \(len(i)\) 只需要加上 26 个字母的 \(lcp\) 即可.

实现
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define int long long
using namespace std;const int N=1<<17,M=48,K=1e6+5;
int n;
int len[N],lcp[N][M],cnt[K][M],dp[N];
string s[M];signed main(){ios::sync_with_stdio(0);cin.tie(0);cin>>n;memset(dp,0x3f,sizeof dp);memset(lcp,0x3f,sizeof lcp);for(int i=0;i<n;i++){cin>>s[i];dp[1<<i]=s[i].size();for(int j:s[i])cnt[i][j-'a']++;}for(int i=0;i<(1<<n);i++){for(int j=0;j<n;j++)if((i>>j)&1)for(int k=0;k<26;k++)lcp[i][k]=min(lcp[i][k],cnt[j][k]);for(int j=0;j<26;j++)len[i]+=lcp[i][j];}for(int i=0;i<(1<<n);i++)for(int j=i;j;j=i&(j-1))dp[i]=min(dp[i],dp[j]+dp[i^j]-len[i]);cout<<dp[(1<<n)-1]+1;return 0;
}

D

见往期笔记.

总结

状压:

题型识别:见字符集想到状压见数据范围想到状压

集合观念:二进制状态表示集合枚举子集进行 dp

其他技巧:预处理思想异或提取子区间

以上.

http://www.gsyq.cn/news/16524.html

相关文章:

  • NKOJ全TJ计划——NP11745
  • Windows install RabbitMQ via PowerShell via administrator role
  • 一些做题记录(2025 2-3)
  • 实用指南:Linux 权限管理入门:从基础到实践
  • 无法定时发送
  • MongoDB财报超预期,文档数据库技术解析
  • 2020CSPS T1 儒略日题解
  • Python 语言编程技巧
  • kafka 常用知识点 - 指南
  • 英语_阅读_ChatGPT_待读
  • 详细介绍:Qwen2.5-VL 损失函数
  • visual studio
  • HttpServletResponse 对象用来做什么? - 详解
  • [LUCKY」在Windows下使用STUN穿透实现Minecraft联机并设置SRV记录
  • 详细介绍:如何用 pnpm patch 给 element-plus 打补丁修复线上 bug(以 2.4.4 修复 PR#15197 为例)
  • Go 为何天生适合云原生? - 指南
  • ARC 207
  • 深入解析:C++:内存管理
  • [KaibaMath1001] 关于∀ε0,|a-b|ε = a=b的证明
  • 基于Web的分布式图集管理系统架构设计与实践 - 教程
  • 国庆 Day2 强基物理
  • unix/linux source 命令,其发展历程详细时间线、由来、历史背景 - 指南
  • AtCoder Regular Contest 207 (Div.1) 游记
  • 详细介绍:云原生时代 Kafka 深度实践:05性能调优与场景实战
  • 从零开始学Flink:数据输出的终极指南
  • 自然语言处理(NLP)的系统学习路径规划 - 实践
  • 【JNI】JNI基础语法
  • 从Chrome渲染器代码执行到内核:MSG_OOB漏洞分析与利用
  • US$78.85 KEYDIY KD ZB42-4 Universal Smart Remote Key 3+1 Buttons for Lexus Type 5pcs/lot
  • Python中小整数对象池、intern机制和大整数对象池