20210804 noip30
考场
第一眼感觉 T1 是状压 DP,弃了。T2 好像也是 DP???看上去 T3 比较可做。
倒序开题。T3 暴力是 \(O(pn\log p)\)(枚举 \(x\),二分答案,看能否分成合法的不超过 \(k\) 组),先写个随机化,和暴力拍了一下发现正确率不太行,退火收敛太慢,只能爬山了,结果还不如直接随机???打表发现峰值特别多。。。死了。强行让退火快速收敛+随机化卡时到 0.98s,拍了拍发现 \(n,p\le5000\) 的时候正确率还行。没注意时间,写完 8.30 了。
T2 完全不会做,直接暴力。手玩数据发现和逆序对有关,但还是只会判无解,后来写了个复杂度不明(也许是 \(O(ans)\))的做法,一分也没骗到。不会造数据,随机了一些发现都是无解。。。爬了
9.30 才开 T1,想了想 DP(根本就不是 DP 啊)就写暴力了。写了 \(O(2^nn\sum m)\) 的暴力,分 \(\sum m\) 的大小用 bitset
或 bool
做背包,发现有一个 \(n=17,m\le2\times10^4\) 的点不会做(其实是 \(O(3^n)\) 枚举每个数不要/放第一个集合/放第二个),一直想到结束。
res
rk14 30+20+50
T3 退火还是太慢,导致后面的点全 T 了。(不然能拿 60~70pts)
rk1 yzf 45+100+50
rk3 牛宏昊 90+20+40
rk5 ycx 75+20+50
rk6 wcr 80+0+60
rk7 刘荣信 15+20+100
rk9 zjj 35+20+70
总结
主要死在了 T1,如果不从 DP 的方向想拿到 70pts 及以上还是比较容易的,以后不要直接确定一个方向,先直接想想,想不出来再根据感觉想特定的算法。
乱搞能力还是太死板,这场的 T1 T3 数据都水,各种做法都能拿到高分甚至 A
毛一琛
meet in the middle
先爆算前 \(\frac n2\) 个数的状态,记下差值和并集。
再枚举后 \(\frac n2\) 个,对于每个差值查和前 \(\frac 2n\) 中和它相同的状态(最多 \(2^{\frac n2}\) 个),然后把两个状态的或计入答案。
时间复杂度 \(O(6^{\frac n2})\)。题解说调整前后的大小能更快,但实测 \(\frac n3,\frac{2n}3\) 都不如 \(\frac n2\)
我选择了用 map
离散化差值,vector
存每个差值的状态,bool
数组去重,貌似不是正解(跑得很慢)
code
const int N = 22;
int n,a[N];
int m,ind,ans;
bool vis[1<<N];
unordered_map<int,int> id;
vector<int> state[1<<N];
void dfs1(int u,int del,int s) {
if( u > m ) {
if( !id.count(del) ) id[del] = ++ind;
state[id[del]].pb(s);
return;
}
dfs1(u+1,del,s);
dfs1(u+1,del+a[u],s|(1<<u-1));
dfs1(u+1,del-a[u],s|(1<<u-1));
}
void dfs2(int u,int del,int s) {
if( u > n ) {
if( !id.count(del) ) return;
int i = id[del];
for(int t : state[i]) vis[s|t] = 1;
return;
}
dfs2(u+1,del,s);
dfs2(u+1,del+a[u],s|(1<<u-1));
dfs2(u+1,del-a[u],s|(1<<u-1));
}
signed main() {
read(n); m = n/2.0;
For(i,1,n) read(a[i]);
dfs1(1,0,0);
dfs2(m+1,0,0);
for(int i = 1, j = 1<<n; i < j; ++i) ans += vis[i];
write(ans);
return iocl();
}
毛二琛
下文将 \([0,n-1]\) 对应到 \([1,n]\)
首先如果有 \(i=p_i\) 那么无解,但数据中没有,所以不用判
问题可以转化为 \(n-1\) 个数排列,对 \(i,i+1\) 的前后顺序有要求(这点保证了每个排列对应一个答案),求方案数。
先处理前后顺序。设 \(cmp[i]=0\) 表示 \(i\) 在 \(i+1\) 的前面,\(=1\) 表示在后面。若 \(i<p_i\),那么 \(cmp[i-1]=1\)(先要把数 \(p_i\) 从 \(i\) 换到 \(i+1\) 才能换 \(i-1,i\)),\(cmp[i..p_i-2]=0\)(数 \(p_i\) 要从 \(i\) 一直向右换到 \(p_i\),期间换了左边的才能换右边,不然数 \(p_i\) 就无法继续向右了),\(cmp[p_i-1]=1\)(换 \(p_i-1,p_i\) 后数 \(p_i\) 一定在 \(p_i\) 上,此后换 \(p_i,p_i+1\) 会导致数 \(p_i\) 被换离);\(i>p_i\) 的情况同理。
考虑 DP。设 \(f[i,j]\) 为前 \(i\) 个数中 \(i\) 排在第 \(j\) 位的方案数,转移:
\sum_{k=j}^{i-1}f[i-1,k],cmp[i-1]=1
\\
\sum_{k=1}^{j-1}f[i-1,k],cmp[i-1]=0
\end{matrix}\right.
\]
\(cmp[i-1]=1\) 时 \(k\in[j,i-1]\) 是因为在前 \(i\) 个数中 \(i-1\) 排在第 \(j\) 位之后,那么在前 \(i-1\) 个数中就要排在 \([j,i-1]\),可以看作将 \(i\) 插进前 \(i-1\) 个数排列的第 \(j\) 位,那么原来的 \(j..i-1\) 位就要向右移一位。第二维可以前缀和优化,时间复杂度 \(O(n^2)\)
code
const int N = 5e3+5, mod = 1e9+7;
int n,a[N];
int f[N][N],sum[N][N];
bool cmp[N];
signed main() {
read(n);
For(i,1,n) read(a[i]), ++a[i];
for(int i = 1; i < n; ++i)
if( i < a[i] ) cmp[i-1] = cmp[a[i]-1] = 1;
else for(int j = a[i]; j < i-1; ++j) cmp[j] = 1;
f[1][1] = sum[1][1] = 1;
for(int i = 2; i < n; ++i) {
if( cmp[i-1] ) For(j,1,i) f[i][j] = (sum[i-1][i-1]-sum[i-1][j-1]+mod)%mod;
else For(j,1,i) f[i][j] = sum[i-1][j-1];
For(j,1,n) sum[i][j] = (sum[i][j-1] + f[i][j]) %mod;
}
write(sum[n-1][n-1]);
return iocl();
}
毛三琛
需要加一个优化:随机枚举 \(x\),\(O(n)\) 判断在当前答案下能否分成不超过 \(k\) 组,如果可以再去二分,时间复杂度 \(O(qn+n\log n\log q)\)
code
const int N = 1e4+5;
int n,p,m,a[N];
int ans,b[N],q[N];
mt19937 mt(time(0));
bool check(int x) {
int res = 1, sum = 0;
For(i,1,n) {
if( b[i] > x ) return 0;
if( sum+b[i] <= x ) sum += b[i];
else ++res, sum = b[i];
}
return res <= m;
}
int calc(int x) {
int l = 1, r = ans;
while( l < r ) {
int mid = l+r>>1;
if( check(mid) ) r = mid;
else l = mid+1;
}
return l;
}
signed main() {
read(n,p,m);
For(i,1,n) read(a[i]), ans += a[i];
for(int i = 0; i < p; ++i) q[i] = i;
shuffle(q,q+p,mt);
for(int i = 0; i < p; ++i) {
For(j,1,n) b[j] = (a[j] + q[i]) %p;
if( check(ans) ) ans = calc(q[i]);
}
write(ans);
return iocl();
}
20210804 noip30的更多相关文章
- noip30
T1 一眼看,觉得是个状压,然而又觉得不太行,去打暴力了,然而暴力都打挂的我biss. 正解: 还是暴力,考虑 \(meet \; in \; the \; middle\) 显然对于每个数,只有三种 ...
- win 常用修复蓝屏,系统比对最后更新20210804
您可以尝试以下方案: 在管理员命令提示符下键入以下命令:Dism /Online /Cleanup-Image /ScanHealth这条命令将扫描全部系统文件并和官方系统文件对比,扫描计算机中的不一 ...
- 调用免费API查询全年工作日、周末、法定节假日、节假日调休补班数据
前言 日常开发中,难免会用到判断今天是工作日.周末.法定节假日.节假日调休补班做一些业务处理,例如:仅在上班时间给用户推送消息.本文记录调用免费API查询全年工作日.周末.法定节假日.节假日调休补班数 ...
- 阿里云RocketMQ定时/延迟消息队列实现
新的阅读体验:http://www.zhouhong.icu/post/157 一.业务需求 需要实现一个提前二十分钟通知用户去做某件事的一个业务,拿到这个业务首先想到的最简单得方法就是使用Redis ...
- SprintBoot简单入门
1.什么是SpringBoot SpringBoot是基于Spring的基础上提供了一套全新的框架,其目的是为了在开发时简化Spring的相关配置及开发过程.在SpringBoot未出来之前,准备搭建 ...
- 用Python预测双色球福利彩票中奖号码(请不要当真)
前言 双色球是中国福利彩票的一种玩法. 红球一共6组,每组从1-33中抽取一个,六个互相不重复.然后蓝球是从1-16中抽取一个数字,这整个组成的双色球 python从零基础入门到实战 今天,我们就用P ...
- 破解加速乐-java
记录一哈自己遇到的简单站点的破解 Talk is cheap,show you the code! import com.google.gson.Gson; import com.google.gso ...
- (11)MySQL进阶篇SQL优化(InnoDB锁问题排查与解决)
1.概述 前面章节之所以介绍那么多锁的知识点和示例,其实最终目的就是为了排查与解决死锁的问题,下面我们把之前学过锁知识重温与补充一遍,然后再通过例子演示下如果排查与解决死锁. 2.前期准备 ●数据库事 ...
- linux centos7 df命令
2021-08-04 1. df 命令简介 linux 中 df 命令的功能是用来检查 linux 服务器的文件系统的磁盘空间占用情况.可以利用该命令来获取硬盘被占用了多少空间,目前还剩下多少空间等信 ...
随机推荐
- DC-9 靶机渗透测试
DC-9 渗透测试 冲冲冲,好好学习 DC系列的9个靶机做完了,对渗透流程基本掌握,但是实战中出现的情况千千万万,需要用到的知识面太广了,学不可以已. 靶机IP: 172.66.66.139 kali ...
- Windows系统安装Mariadb数据库(zip包方式安装)--九五小庞
1.去Mariadb官网下载zip安装包 下载地址:https://downloads.mariadb.org/mariadb/10.3.31/ 2.解压压缩包到指定的安装位置 3.在安装包的data ...
- icmp介绍以及arp攻击
目录 一.ip数据包格式 二.ICMP协议介绍 三.ARP协议介绍 四.ARP攻击原理 一.ip数据包格式 网络层的功能: 定义了基于ip协议的逻辑地址 连接不同的媒介类型 选择是数据通过网络的最佳途 ...
- 从事 Android应用开发4年有余,现在工资7500。很不爽!怎么办?
最近到某论坛看到一个帖子: 坐标北京,在一个公司从事android应用开发4年有余(毕业至今没换过公司).公司利润越来越大,工资却每年长1000,如今才到7500.琢磨着换工作,又不想扔下这四年来逐步 ...
- Promise/A+规范-翻译
Promise 表示一个异步操作的最终结果,与之进行交互的方式主要是 then 方法,该方法注册了两个回调函数,用于接收 promise 的终值或本 promise 不能执行的原因. 本规范详细列出了 ...
- 学习vue过程中遇到的问题
1.vue-quill-editor动态禁用 项目中把vue-quill-editor单独封装成了一个组件,通过props传递readOnly参数来设置是否禁用editor.开发中发现可以实现禁用效果 ...
- Spring IOC容器核心流程源码分析
简单介绍 Spring IOC的核心方法就在于refresh方法,这个方法里面完成了Spring的初始化.准备bean.实例化bean和扩展功能的实现. 这个方法的作用是什么? 它是如何完成这些功能的 ...
- docker容器dockerfile详解
docker公司在容器技术发展中提出了镜像分层的理念,可以说也是这个革命性的理念让原本只不过是整合linux内核特性的容器,开始野蛮生长. docker通过UnionFS联合文件系统将镜像的分层实现合 ...
- 🏆【Java技术专区】「开发实战专题」Lombok插件开发实践必知必会操作!
前言 在目前众多编程语言中,Java 语言的表现还是抢眼,不论是企业级服务端开发,还是 Andorid 客户端开发,都是作为开发语言的首选,甚至在大数据开发领域,Java 语言也能占有一席之地,如Ha ...
- 有关SQL注入的一些小知识点
1.判断注入点: 本质原理是找一个需要后台处理后,提交给数据库的点,我理解为用户可以控制并输入后台数据库的变量,比如我们DVWA SQL injection 的ID ,我们可以通过闭合单引号,#注释 ...