CF Round 1005 题解合集
困难场。
C
考虑贪心,我们在一个前缀只取正数,后缀只取负数,这样取一定可以取到最大值。
扫一遍记录前缀正数和和后缀负数和,枚举分割点即可。
复杂度 。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int t,n,a[200005],pre[200005],suf[200005],ans;
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
if(a[i]>=0) pre[i]=pre[i-1]+a[i];
else pre[i]=pre[i-1];
}
for(int i=n;i>=1;i--){
if(a[i]>=0) suf[i]=suf[i+1];
else suf[i]=suf[i+1]-a[i];
}
for(int i=0;i<=n;i++){
ans=max(ans,pre[i]+suf[i+1]);
}
cout<<ans<<'\n';
ans=0;
for(int i=0;i<=n+1;i++){
pre[i]=suf[i]=0;
}
}
return 0;
}
D
一个观察: 的最高位 只会左移。
同时,如果 的最高位 比 的最高位 靠右,那么 一定会被吃。
所以考虑只有在 的最高位 大于等于 的最高位 时,再考虑 是否合法。
容易发现,这样的位置只有 个。
为了确定这样的 的位置,考虑预处理跳跃数组: 表示从 往前跳,第一个最高位 的位置。
为了得知 跳一个区间的异或和,考虑预处理异或前缀和数组。
然后就可以暴力跳了,注意边界的细节。
复杂度 。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int t,n,m,x,a[200005],f[200005][31],cnt[31],sum[200005],p,q;
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n+1;i++){
for(int j=0;j<=30;j++){
f[i][j]=cnt[j];
}
for(int j=30;j>=0;j--){
if(a[i]&(1<<j)){
p=j;
break;
}
}
for(int j=0;j<=p;j++){
cnt[j]=i;
}
}
for(int i=n;i>=1;i--){
sum[i]=sum[i+1]^a[i];
}
for(int i=1;i<=m;i++){
cin>>x;
p=n+1;
for(int j=30;j>=0;j--){
if(x&(1<<j)){
q=f[p][j];
if(!q){
p=q+1;
break;
}
if((x^sum[p]^sum[q+1])>=a[q]){
x^=(sum[p]^sum[q]);
p=q;
}else{
p=q+1;
break;
}
}
}
cout<<n-p+1<<' ';
}
cout<<'\n';
for(int i=0;i<=30;i++){
cnt[i]=0;
}
for(int i=1;i<=n+1;i++){
sum[i]=0;
for(int j=0;j<=30;j++){
f[i][j]=0;
}
}
}
return 0;
}
E
做了半个下午,太困难。
观察一:。
第一列就是 ,不会改变。
观察二: 是颜色相同的若干位置交换得到的。
可以通过每个颜色块的位置,确定每个颜色 的每一行数量集合,同一颜色的 只会交换位置,不会改变值。
观察三: 的 能够交换,当且仅当 。
手玩几下样例就能看出来。
然后就差不多了。
考虑对于一个位置 ,它能交换的位置集合是一段区间。
不难发现,对于同一种颜色,这些区间只有相互包含和不交两种可能,并且一定是 大的包含 小的。
最终的合法方案是每个点在区间内选择一个,可以从下往上用乘法原理计算。
然后就可以从小到大枚举一种颜色中的所有位置,用并查集维护这个树形结构,合并时计算答案。
实现上,还需要线段树计算每个节点的交换区间。
复杂度 。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=998244353;
int t,n,ord[200005],p[200005],c[200005];
vector<int> v[200005],o[200005];
bool cmp(int x,int y){
return p[x]<p[y];
}
int fa[200005],siz[200005],L[200005],R[200005],ans;
void init(){
for(int i=1;i<=n;i++){
fa[i]=i;
siz[i]=1;
}
}
int find(int x){
if(fa[x]==x) return x;
else return fa[x]=find(fa[x]);
}
void merge(int x,int y){
x=find(x);
y=find(y);
if(x==y) return;
fa[x]=y;
siz[y]+=siz[x];
L[y]=min(L[y],L[x]);
R[y]=max(R[y],R[x]);
}
int val[400005],ls[400005],rs[400005],dcnt,rt;
void pushup(int x){
val[x]=max(val[ls[x]],val[rs[x]]);
}
void build(int l,int r,int &x){
x=++dcnt;
if(l==r){
val[x]=p[l];
return;
}
int mid=(l+r)>>1;
build(l,mid,ls[x]);
build(mid+1,r,rs[x]);
pushup(x);
}
void modify(int l,int r,int pos,int k,int x){
if(l==r){
val[x]=k;
return;
}
int mid=(l+r)>>1;
if(pos<=mid) modify(l,mid,pos,k,ls[x]);
else modify(mid+1,r,pos,k,rs[x]);
pushup(x);
}
int query(int l,int r,int ql,int qr,int x){
if(ql<=l && r<=qr) return val[x];
int mid=(l+r)>>1,ans=0;
if(ql<=mid) ans=max(ans,query(l,mid,ql,qr,ls[x]));
if(qr>=mid+1) ans=max(ans,query(mid+1,r,ql,qr,rs[x]));
return ans;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--){
ans=1;
cin>>n;
for(int i=1;i<=n;i++){
cin>>p[i];
}
for(int i=1;i<=n;i++){
cin>>c[i];
L[i]=R[i]=v[c[i]].size();
v[c[i]].push_back(i);
o[c[i]].push_back(i);
}
for(int i=1;i<=n;i++){
sort(o[i].begin(),o[i].end(),cmp);
}
init();
build(1,n,rt);
for(int i=1;i<=n;i++){
for(int j=0;j<o[i].size();j++){
modify(1,n,o[i][j],0,rt);
}
for(int j=0;j<o[i].size();j++){
int k=lower_bound(v[i].begin(),v[i].end(),o[i][j])-v[i].begin();
for(int l=k-1;l>=0;l--){
if(query(1,n,v[i][l],v[i][k],rt)>=p[v[i][k]]) break;
merge(v[i][k],v[i][l]);
l=L[find(v[i][k])];
}
for(int l=k+1;l<v[i].size();l++){
if(query(1,n,v[i][k],v[i][l],rt)>=p[v[i][k]]) break;
merge(v[i][k],v[i][l]);
l=R[find(v[i][k])];
}
ans=ans*siz[find(v[i][k])]%mod;
siz[find(v[i][k])]--;
}
for(int j=0;j<o[i].size();j++){
modify(1,n,o[i][j],p[o[i][j]],rt);
}
}
cout<<ans<<'\n';
dcnt=0;
for(int i=1;i<=n;i++){
o[i].clear();
v[i].clear();
}
for(int i=1;i<=n;i++){
fa[i]=0;
L[i]=0;
R[i]=0;
}
}
return 0;
}
本文作者:Kenma
本文链接:https://www.cnblogs.com/Kenma/p/18720239
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步