atcoder 杂题 #04

news/2024/12/19 22:01:31/文章来源:https://www.cnblogs.com/dccy/p/18618006

atcoder 杂题 #04

  • abc126_f XOR Matching
  • arc081_d Flip and Rectangles
  • arc080_c Young Maids
  • abc383_g Bar Cover

abc126_f

挺有意思的一道题,让我猜到结论了。

由于长度是值域的两倍,所以不难想到每个数出现两次,不然发现对于 \(a_i=a_j=a_k\) 的三个数,当 \(a_i\oplus \cdots\oplus a_j=a_j\oplus \cdots\oplus a_k=K\) 时,一定有 \(a_i\oplus \cdots\oplus a_k=a_j=K\),此时就无法构造了。

首先 \(K=0\) 的情况就是 \(0,0,1,1,\cdots,2^m-1,2^m-1\)
对于 \(K\ge2^m\) 则无解。

由于我们要让异或和为 \(K\),不妨让 \(K\) 放中间,然后每次往两边添加两个相同的数,最后在一边再添加 \(K\),这就要求 $ \oplus_{i=0}{2m-1} i=0$,才能使两个 \(K\) 之间的异或和为 \(K\)
即形如 \(0,1,2,\cdots ,2^m-1,K,2^m-1,\cdots,2,1,0,K\)

做这道题的时候认为异或和不为 0 就是无解。
但写到这才发现由于范围是 \(0\sim 2^m-1\),所以异或和必定为 0,所以我们的构造方式是正确的。

AC 代码:

int n,m;
signed main(){cin>>n>>m;if(m==0){fu(i,0,1<<n)cout<<i<<' '<<i<<" ";return 0;}int s=0;fu(i,0,1<<n)s^=i;if(s==0&&m<(1<<n)){fu(i,0,1<<n)if(i!=m)cout<<i<<" ";cout<<m<<" ";fd(i,(1<<n)-1,0)if(i!=m)cout<<i<<" ";cout<<m<<" ";return 0;}else cout<<"-1";return 0;
}

arc081_d

没有想出来。

其实是一个经典结论,考虑怎样的矩形满足可以经过翻转行和列使得变成全 1 的矩形。

结论就是,如果一个矩形内所有 \(2\times 2\) 的子矩形中 1 和 0 都是偶数个(即异或和为 0),那么这个矩形就是合法的。

证明:
对于一个 \(n\times m\) 的矩形,有 \(2^{n+m}\) 个矩形满足可以从全 1 的矩形得到,这些矩形都是合法的。
我们又发现,合法的矩形一定满足每行都与第一行每位相同或每位相反,列也同理。因为从全 1 矩形开始操作,无论怎么操作都满足这个性质。
于是每行也与上一行每位相同或每位相反,因此可以得到,合法的矩形满足每个 \(2\times 2\) 的矩形异或和为 0。
这就证明了必要性,充分性呢?
发现如果确定了第一行和第一列,那么根据 \(2\times 2\) 子矩形异或和为 0 的性质,其他位置也都确定了。
而确定第一行和第一列的方式恰好是 \(2^{n+m}\) 种,于是每一种满足 \(2\times 2\) 子矩形异或和为 0 的矩形,都是合法矩形。

然后怎么做呢?

考虑根据每一个 \(2\times 2\) 的子矩形是否合法构造一个新的矩阵,然后就是求面积最大的子矩阵,这是经典问题,可以使用单调栈在 \(O(n^2)\) 解决。

AC 代码:

const int N=2005;
char a[N][N];
int c[N][N];
int n,m;
pair<int,int> stk[N];
int top,l[N],r[N];
signed main(){read(n,m);fo(i,1,n)fo(j,1,m)read(a[i][j]);fu(i,1,n)fu(j,1,m){int x=a[i][j]^a[i+1][j]^a[i][j+1]^a[i+1][j+1];if(x==0)c[i][j]=c[i-1][j]+1;}int ans=max(n,m);fu(i,1,n){top=0;fu(j,1,m){l[j]=r[j]=j;while(top&&stk[top].first>=c[i][j])--top;l[j]=stk[top].second;stk[++top]={c[i][j],j};}stk[top=1]={-1,m};fd(j,m-1,1){while(top&&stk[top].first>=c[i][j])--top;r[j]=stk[top].second;stk[++top]={c[i][j],j};		if(c[i][j])ans=max(ans,(c[i][j]+1)*(r[j]-l[j]));}}write(ans);return 0;
}

arc080_c

好题。

首先这种字典序最小就是贪心,由于每次是往前面加,所以考虑倒序。

考虑如果选择 \(i,j(i<j)\),那么在正序时就表现其他都选完了后,再选了它们。

那么第一次选择 \(i,j\) 合法当且仅当 \([1,i-1],[i+1,j-1],[j+1,n]\) 都是偶数长度。

\(i\) 为奇数,\(j\) 为偶数。

发现这三个区间的问题是互相独立的,可以递归求解。

每次在 \([L,R]\) 选择 \(i,j\) 就要满足 \(i\)\(L\) 的奇偶性相同,\(j\)\(L\) 的奇偶性不同。

考虑怎么快速求出一个区间内最优的 \(i,j\)

贪心地,选出奇数(或偶数)位上最小的数作为 \(i\),由于区间长度是偶数,\(i\) 后面一定至少选出一个 \(j\),把 \(i\) 后面与 \(i\) 奇偶性不同的位中取最小值作为 \(j\) 即可,可以用 ST 表维护奇数(偶数)位的区间最小值,同时也可以得到最小值所在的位置。

考虑怎么合并每个子区间,发现直接合并类似于归并的过程,然而每次的时间都是合并的两个区间长度之和,时间复杂度不能接受。

考虑求出所有 \(i,j\) 对后,从大区间往小区间做。开始 \([1,n]\)\(i,j\) 对丢进堆里,每次从堆里选完一个区间 \(i,j\) 后,把每个子区间的 \(i,j\) 丢进堆里,因为子区间要在父区间之后选。

时间复杂度的瓶颈在于预处理 ST 表和最后的堆,为 \(O(n\log n)\)

AC 代码:

const int N=2e5+5;
int n;
int a[N];
struct S_list{pair<int,int> mn[18][N];pair<int,int> get(int l,int r){int len=r-l+1;return min(mn[__lg(len)][l],mn[__lg(len)][r-(1<<__lg(len))+1]);}void make(){fo(i,1,__lg(n)){fo(j,1,n-(1<<i)+1){mn[i][j]=min(mn[i-1][j],mn[i-1][j+(1<<i-1)]);}}}
}s[2];
vector<int> g[N];
int ans1[N],ans2[N];
int tot;
int solve(int l,int r){int x=++tot;int opt=l&1;auto t1=s[opt^1].get(l,r);auto t2=s[opt].get(t1.second+1,r);ans1[x]=t1.first,ans2[x]=t2.first;if(t1.second>l)g[x].push_back(solve(l,t1.second-1));if(t1.second+1<t2.second)g[x].push_back(solve(t1.second+1,t2.second-1));if(t2.second<r)g[x].push_back(solve(t2.second+1,r));return x;
}
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<> > q;
signed main(){cin>>n;fo(i,1,n){cin>>a[i];s[0].mn[0][i]=s[1].mn[0][i]={N,N};if(i&1)s[0].mn[0][i]={a[i],i};else s[1].mn[0][i]={a[i],i};}s[0].make(),s[1].make();solve(1,n);q.push({ans1[1],1});while(q.size()){int u=q.top().second; q.pop();cout<<ans1[u]<<" "<<ans2[u]<<' ';for(auto v:g[u]){q.push({ans1[v],v});}}return 0;
}

abc383_g

若干个经典结论。

我们先把每 \(K\) 个数的和构成一个新的数组,要求对每个 \(x\) 求出选 \(x\) 个数且两两之间必须间隔 \(K-1\) 个数,问最大和。

考虑分治,我们对于每个区间 \([L,R]\) 求出 \(f_{i,j,k}\) 表示区间左边有 \(i\) 个数没选,右边有 \(j\) 个数没选,选了 \(k\) 个数且这些数已合法的最大和。

那么我们枚举 \(i,j\) 后考虑合并两个区间的数组,每个数组都是一个值关于 \(k\) 的上凸函数,感性理解就是选的越多加的越少。

合并两个凸函数可以做到 \(O(Len)\),其中 \(Len\) 是定义域。这是一个经典结论,具体地,如果我们知道 \(f_i+g_j\to h_{i+j}\) 是转移到 \(i+j\) 最优的 \(i,j\),那么转移到 \(h_{i+j+1}\) 最优的 \(i,j\) 一定是 \(f_{i+1}+g_{j}\)\(f_{i}+g_{j+1}\),取最大的作为新的 \(i,j\) 即可。

计算时间复杂度,枚举两边每选的 \(O(K^2)\),枚举中间没选的 \(O(K)\),因为两个区间中间没选的和为 \(K-1\),枚举一个即可。然后枚举选的个数 \(O(\frac n K)\),再乘上分治的 \(O(\log n)\) 层。
于是总的就是 \(O(n K^2\log n)\)

AC 代码:

const int N=2e5+5;
const ll inf=0x3f3f3f3f3f3f3f3fll;
int n,K;
int a[N];
ll b[N];
struct arr{vector<ll> f[5][5];
};
void mx(ll &x,ll y){x=max(x,y);
}
void solve(arr &x,int l,int r){int sz=(r-l+K)/K+1;fu(i,0,5)fu(j,0,5)x.f[i][j]=vector<ll>(sz,-inf);if(l==r){x.f[0][0][1]=b[l];return;}arr L,R;int mid=(l+r)>>1;int ls=(mid-l+K)/K+1,rs=(r-mid-1+K)/K+1;solve(L,l,mid),solve(R,mid+1,r);fu(i,0,5)fu(j,0,5){fu(p,1,sz){if(p<ls)mx(x.f[i][min(4,j+r-mid)][p],L.f[i][j][p]);if(p<rs)mx(x.f[min(4,i+mid-l+1)][j][p],R.f[i][j][p]);}fu(k,0,K){int y=0,z=0;fu(p,1,sz){if(y+1==ls)++z;else if(z+1==rs)++y;else if(L.f[i][k][y+1]+R.f[K-1-k][j][z]>L.f[i][k][y]+R.f[K-1-k][j][z+1])++y;else ++z;if(y<ls&&z<rs)mx(x.f[i][j][p],L.f[i][k][y]+R.f[K-1-k][j][z]);}}}fd(i,4,0)fd(j,3,0)fu(p,1,sz)mx(x.f[i][j][p],x.f[i][j+1][p]);fd(j,4,0)fd(i,3,0)fu(p,1,sz)mx(x.f[i][j][p],x.f[i+1][j][p]);
}
signed main(){cin>>n>>K;fo(i,1,n)cin>>a[i];fo(i,K,n)fo(j,i-K+1,i)b[i]+=a[j];arr Main;solve(Main,K,n);fo(i,1,n/K){ll ans=-inf;fu(j,0,5)fu(k,0,5)mx(ans,Main.f[j][k][i]);cout<<ans<<' ';}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/855613.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

图床试验

本文来自博客园,作者:Glowingfire,转载请注明原文链接:https://www.cnblogs.com/Glowingfire/p/18617999

一文搞定理解RPC

前言RPC概念RPC协议RPC组成RPC协议RPC框架RPC的优点RPC与HTTP的区别 前言 RPC的概念相信很多软件从业人员或多或少都接触过,从开发到测试都可能需要跟它打交道。 但是对于为什么要用RPC?RPC的优点是什么?RPC是什么原理?它跟HTTP有什么不同?相信并不是每个人都比较熟悉。 那…

全场景一站式2024最新vmware环境下安装win7并且破解QTP

目录VMwareVMware和Ubuntu下载链接下载Win 7 系统各个操作系统网站激活码是什么查看是否激活激活操作vmware下安装ubuntu创建虚拟机下载VMtool灰色灰色按键点击不了下载提示有问题原因文件传递共享文件借助外界U盘有了VMTool就可以直接拖拽!!!!有了VMTool就可以全屏化——倒…

20222321 2024-2025-1 《网络与系统攻防技术》实验八实验报告

一.实验内容 (1)Web前端HTML 能正常安装、启停Apache。理解HTML,理解表单,理解GET与POST方法,编写一个含有表单的HTML。 (2)Web前端javascipt 理解JavaScript的基本功能,理解DOM。 在(1)的基础上,编写JavaScript验证用户名、密码的规则。在用户点击登陆按钮后回显“欢迎…

数量

技巧 比例型 出现一个比例,存在四种倍数关系倍数 你们有啥公因子,我也必须有尾数 出现乘法,分析个位,考虑尾数 。乘法中出现5和10尾数就确认了奇偶 与偶数相乘一定是偶数,与奇数相乘可能为偶数也可能为奇数拓展猜题 当 A = B*C ,求A ,考虑A的倍数 工程问题 利润问题 求最…

LVGL学习 - Visual Studio外部“.c.h”文件添加

LVGL项目工程添加“.c.h”文件后 “C1083”“LNK2019”报错的解决方法一、首先把文件添加至工程,现有项选择所需添加的“.c.h”文件但还是会有如下报错,解决方法在第2步。二、“.c”文件需要添加“extern "C"” 下图截至官方文档我试了只添加“extern "C"…

组合数学+ybt题解

加法原理 乘法原理 排列数 从 \(n\) 个数中任取 \(m\) 个元素的排列的方案数,表示为 \(A^m_n=\frac{n!}{(n-m)!}\) \(0!=1\) 全排列 \(A^n_n\) 组合数 从 \(n\) 个元素中取出 \(m\) 个元素的组合的个数,表示为 \(\dbinom{n}{m}= \frac{A^m_n}{m!}=\frac{n!}{m!(n-m)!}\) 如何…

苍穹外卖day02

JWT令牌、ThreadLocal、分页查询bug记录知识点记录新增员工新增员工需要填写创建人id和修改人id两个属性,这两个属性应该填本账户的id。 通过拦截器可以解析出JWT令牌中包含的登录员工id信息,但是该如何传递给Service的save方法? ThreadLocal并非一个Thread,而是Thread的局…

年底裁员开始了,大家做好准备吧!

各大互联网公司的接连裁员,政策限制的行业接连消失,让今年的求职雪上加霜,想躺平却没有资本,还有人说软件测试岗位饱和了,对此很多求职者深信不疑,因为投出去的简历回复的越来越少了。 另一面企业招人真的变得容易了吗?有企业HR吐槽,简历确实比以前多了好几倍,其实是变…

2024-2025-1 20241401 《计算机基础与程序设计》 第十三周学习总结

班级链接 2024计算机基础与程序设计作业要求 第十三周作业教材学习内容总结 《C语言程序设计》第12章结构体的定义和使用: 结构体类型的定义,以及结构体变量的创建和使用。结构体允许将不同数据类型的成员组合成一个整体,以便于管理和引用。 结构体变量的初始化: 结构体变量…