CF2064E Mycraft Sand Sort 题解
第一次一眼秒了一道 E,但是被人均六分钟 C 题硬控一小时,未能写完,遗憾离场,特此纪念。
考虑第一列,无论排列 \(p'\) 是什么样子,第一列一定是 \(c'\)。因此,\(c'\) 数组一定等于 \(c\) 数组。
这个结论还引出一个推论,\(p'\) 一定由 \(p\) 中颜色相同的位置交换得到。如果异色交换,一定会有一种颜色的方块总数变化,此时一定不与初始状态相同。
那我们先考虑一种颜色。一种颜色某个元素可以邻项交换的条件是这两个元素之间的位置大小必须都小于这个位置的大小。手玩一下充分性是显然的,考虑之间的位置大小大于的情况一定会导致某两个方块颜色改变,所以也是必要的。
那么,一个元素可以交换的位置是一段连续的区间,即左右都到第一个大于这个元素的异色位置。这种计数问题的经典做法是先考虑最紧的限制。我们先考虑最小的元素,从小到大依次安排位置。当我们安排一个更大的元素时,这个元素的区间要么和之前的区间无交,要么完全包含。我们把占位置的贡献挂到每段可行区间的左端点,统计有多少个位置已经被占只需要查询可行区间的区间和即可。
然后我们发现每种颜色是独立的,我们先交换小的元素,这样就不会被后来交换的元素影响,一定存在方案。直接乘起来就行了。
上面提到的东西都可以使用线段树维护,使用普通二分时间复杂度 \(O(n\log^2 n)\),使用线段树二分时间复杂度 \(O(n\log n)\)。
#include <bits/stdc++.h>
#define lc(x) ((x)<<1)
#define rc(x) ((x)<<1)|1
using namespace std;
struct node
{
long long mx,sum;
}tr1[1200000],tr2[1200000];
long long t,n,p[300000],c[300000],rt=1;
vector<long long>a[300000];
pair<long long,long long>b[300000];
const long long mod=998244353;
void pushup(struct node tr[],long long x)
{
tr[x].mx=max(tr[lc(x)].mx,tr[rc(x)].mx);
tr[x].sum=tr[lc(x)].sum+tr[rc(x)].sum;
}
void build1(long long x,long long l,long long r)
{
tr1[x].mx=tr1[x].sum=0;
if(l==r)
{
tr1[x].mx=p[l];
return;
}
long long mid=(l+r)>>1;
build1(lc(x),l,mid),build1(rc(x),mid+1,r);
pushup(tr1,x);
}
long long query1(long long x,long long l,long long r,long long lx,long long rx)
{
if(lx>rx)return 0;
if(l>=lx&&r<=rx)return tr1[x].mx;
long long mid=(l+r)>>1,ans=0;
if(lx<=mid)ans=max(ans,query1(lc(x),l,mid,lx,rx));
if(rx>=mid+1)ans=max(ans,query1(rc(x),mid+1,r,lx,rx));
return ans;
}
void build2(long long x,long long l,long long r,long long c)
{
tr2[x].mx=tr2[x].sum=0;
if(l==r)
{
tr2[x].mx=query1(rt,1,n,a[c][l-1]+1,a[c][l]-1);
return;
}
long long mid=(l+r)>>1;
build2(lc(x),l,mid,c),build2(rc(x),mid+1,r,c);
pushup(tr2,x);
}
void add(long long x,long long l,long long r,long long p,long long k)
{
if(l==r)
{
tr2[x].sum+=k;
return;
}
long long mid=(l+r)>>1;
if(p<=mid)add(lc(x),l,mid,p,k);
else add(rc(x),mid+1,r,p,k);
pushup(tr2,x);
}
long long query2(long long x,long long l,long long r,long long lx,long long rx)
{
if(lx>rx)return 0;
if(l>=lx&&r<=rx)return tr2[x].mx;
long long mid=(l+r)>>1,ans=0;
if(lx<=mid)ans=max(ans,query2(lc(x),l,mid,lx,rx));
if(rx>=mid+1)ans=max(ans,query2(rc(x),mid+1,r,lx,rx));
return ans;
}
long long query3(long long x,long long l,long long r,long long lx,long long rx)
{
if(lx>rx)return 0;
if(l>=lx&&r<=rx)return tr2[x].sum;
long long mid=(l+r)>>1,ans=0;
if(lx<=mid)ans=ans+query3(lc(x),l,mid,lx,rx);
if(rx>=mid+1)ans=ans+query3(rc(x),mid+1,r,lx,rx);
return ans;
}
int main()
{
scanf("%lld",&t);
while(t--)
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)a[i].clear(),a[i].push_back(0);
for(int i=1;i<=n;i++)scanf("%lld",&p[i]);
for(int i=1;i<=n;i++)scanf("%lld",&c[i]),a[c[i]].push_back(i);
build1(rt,1,n);
long long ans=1;
for(int i=1;i<=n;i++)
if(a[i].size()>1)
{
long long w=a[i].size()-1;
build2(rt,1,w,i);
for(int j=1;j<=w;j++)b[j].first=p[a[i][j]],b[j].second=j;
sort(b+1,b+w+1);
for(int j=1;j<=w;j++)
{
long long l=1,r=b[j].second-1,lx=r+1,rx=r+1;
while(l<=r)
{
long long mid=(l+r)>>1;
if(query2(rt,1,w,mid+1,b[j].second)<b[j].first)lx=mid,r=mid-1;
else l=mid+1;
}
l=b[j].second+1,r=w;
while(l<=r)
{
long long mid=(l+r)>>1;
if(query2(rt,1,w,b[j].second+1,mid)<b[j].first)rx=mid,l=mid+1;
else r=mid-1;
}
ans=ans*(rx-lx+1-query3(rt,1,w,lx,rx))%mod,add(rt,1,w,lx,1);
}
}
printf("%lld\n",ans%mod);
}
return 0;
}
CF2064E Mycraft Sand Sort 题解的更多相关文章
- codechef Turbo Sort 题解
Input t – the number of numbers in list, then t lines follow [t <= 10^6]. Each line contains one ...
- 洛谷 P2945 [USACO09MAR]沙堡Sand Castle 题解
题目传送门 大概思路就是把这两个数组排序.在扫描一次,判断大小,累加ans. #include<bits/stdc++.h> using namespace std; int x,y,z; ...
- LuoguP7259 [COCI2009-2010#3] SORT 题解
Content 请编写一个"频率排序器".输入一个 长度为 \(n\) 的数列 \(A=\{a_1,a_2,\dots,a_n\}\),要求: 按照每个数的出现次数降序排列. 如果 ...
- HDU 1425 sort 题解
选择出数列中前k个最大的数. 这里由于数据特殊.所以能够使用hash表的方法: #include <cstdio> #include <algorithm> #include ...
- Hdoj 1425.sort 题解
Problem Description 给你n个整数,请按从大到小的顺序输出其中前m大的数. Input 每组测试数据有两行,第一行有两个数n,m(0<n,m<1000000),第二行包含 ...
- Insertion Sort List Leetcode java
题目: Sort a linked list using insertion sort. 题解: Insertion Sort就是把一个一个元素往已排好序的list中插入的过程. 初始时,sorted ...
- 【leetcode刷题笔记】Insertion Sort List
Sort a linked list using insertion sort. 题解:实现链表的插入排序. 要注意的地方就是,处理链表插入的时候尽量往当前游标的后面插入,而不要往前面插入,后者非常麻 ...
- 算法与数据结构基础 - 排序(Sort)
排序基础 排序方法分两大类,一类是比较排序,快速排序(Quick Sort).归并排序(Merge Sort).插入排序(Insertion Sort).选择排序(Selection Sort).希尔 ...
- 830. String Sort
830. String Sort 题解 int alpha[256] = {0};//记录字符的次数 bool cmp(char a,char b) { if(alpha[a]==alpha[b])/ ...
- 【AtCoder】ARC088
C - Multiple Gift 题解 首项是X,每次乘个2,暴力统计 代码 #include <bits/stdc++.h> #define fi first #define se s ...
随机推荐
- 干货分享!MCP 实现原理,小白也能看懂
不知道大家有没有发现?对于添加到 MCP 服务市场的成千上万个 MCP 服务(而且这个数字每天还在增加),我们可以不写一行代码,轻松实现调用,但背后的原因究竟是啥呢? MCP 虽然用起来很方便,但搞不 ...
- redis-dump教程
1.安装ruby 安装教程:https://www.cnblogs.com/wanyuan/p/11217397.html 安装完成后在DOS窗口输入ruby -v查看当前版本 2.安装redis-d ...
- Reactjs之Vue用户0基础上手Reactjs笔记
Reactjs之Vue用户0基础上手Reactjs笔记 - 搜栈网 (seekstack.cn)https://www.seekstack.cn/post/382
- 解密prompt系列53. 再谈大模型Memory
上一章畅想里面我们重点提及了大模型的记忆模块,包括模型能否持续更新记忆模块,模型能否把持续对记忆模块进行压缩更新在有限的参数中存储更高密度的知识信息,从而解决有限context和无限知识之间的矛盾.这 ...
- EFCore——树形结构篇
1.整体数据量不大的场景 参照:EntityFramework Linq 查询数据获得树形结构-YES开发框架网 (yesdotnet.com) 核心方法GetChildData,特点将所有的数据查到 ...
- EFCore先DBFirst,再CodeFirst(针对老项目迁移)
参照文章: CodeFirst命令介绍:Scaffold-DbContext 命令使用 - 跟着阿笨一起玩.NET - 博客园 (cnblogs.com) 整体流程介绍:NetCore 中 EFcor ...
- 用DevEco Studio增量补丁修复功能,让鸿蒙应用的调试效率大增
在鸿蒙应用开发的快节奏赛道上,每一秒的开发效率提升都至关重要.如何更快地看到代码更改后的效果?如何尽可能缩短开发.调试和验证的周期?如何做到在某大厂180万行+项目中将代码修改即时生效?这些问题在De ...
- 使用DbUtils和dbcp连接池写的通用的CRUD工具类
目录 1 项目目录结构 2 工具类需要的jar包 2.1 Dbutils需要的jar包 2.2 dbcp需要的jar包 2.3 数据库jar包 3 代码部分 3.1 dbcp.properties 3 ...
- Windows tomcat简单使用
目录 1 常见服务器 2 Tomcat下载安装 3 配置环境 3.1 jdk环境 3.2 tomcat环境 4 启动/关闭 tomcat 5 访问tomcat 6 修改tomcat端口 7 部署项目 ...
- ARM终端 KylinOS 容器镜像导入排障
背景信息 电脑:华为擎云L420 CPU:ARM架构,HUAWEI Kirin 9006C OS:Kylin桌面操作系统V10(SP1) Kernel:5.4.96 Docker: 27.5.1 已准 ...