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 服务器的文件系统的磁盘空间占用情况.可以利用该命令来获取硬盘被占用了多少空间,目前还剩下多少空间等信 ...
随机推荐
- mysql查看当前连接数
show status like 'Threads%'; 需要root权限才能看到所有的连接
- 图解 HTTP 连接管理
熟悉我的小伙伴都知道,我之前肝了本<HTTP 核心总结>的 PDF,这本 PDF 是取自我 HTTP 系列文章的汇总,然而我写的 HTTP 相关内容都是一年前了,我回头看了一下这本 PDF ...
- CSS中content属性的妙用
前言 本文讲解CSS中使用频率并不高的content属性,通过多个实用的案例,带你由浅入深的掌握content的用法,让代码变得更加简洁.高效. 定义 W3school中这样定义: content 属 ...
- TypeScript学习笔记(四)装饰器
目录 一.装饰器的作用 二.类装饰器 1. 普通装饰器 为类扩展属性和方法 使用装饰器修改属性和重写方法 2. 装饰器工厂 三.属性装饰器 四.方法装饰器 使用方法装饰器对方法进行扩展 五.方法参数装 ...
- kali linux 的ssh服务器拒绝了密码 请再试一次
1.配置kali linux下的SSH,默认情况下kali下的SSH不允许root用户远程登录SSH,需要修改配置文件 /etc/ssh/sshd_config,修改PermitRootLogin y ...
- Arp欺骗和DNS投毒
中间人攻击 ARP缓存攻击 ARP(Address Resolution Protocol,地址解析协议)是一个位于TCP/IP协议栈中的网络层,负责将某个IP地址解析成对应的MAC地址.简单来说,就 ...
- 虚拟机中桥接模式和NAT模式以及仅主机模式的区别
桥接模式和NAT模式 网络连接类型的选择,网络连接类型一共有桥接.NAT.仅主机和不联网四种. 桥接:选择桥接模式的话虚拟机和宿主机在网络上就是平级的关系,相当于连接在同一交换机上. NAT:NAT模 ...
- 记录一次mysql的安装之旅
mysql作为日常开发中常用到的数据库,对每个程序员来说至关重要,今天就跟着我来进行一次mysql的安装之旅吧. 一.安装 1.安装包的方式 1.1.获取安装包 对mysql有过接触的人来说,都知道m ...
- JavaScript学习01(js概述)
JavaScript概述 JavaScript历史 要了解JavaScript,我们首先要了解一下JavaScript的诞生. 在上个世纪的1995年,当时的网景公司正凭借其Navigator浏览器成 ...
- 【Java】@Scheduled常用的注解的使用
@Scheduled注解的使用 cron cron这个参数必须要接受一个cron表达式 cron表达式是个啥呢,Cron表达式是一个具有时间含义的字符串,字符串以5个空格隔开,分为6个域,格式为 X ...