多校A层冲刺NOIP2024模拟赛09

考试唐完了,T2、T4 都挂了 100 分,人麻了。

排列最小生成树

给定一个 \(1, 2,\dots , n\) 的排列 \(p_1, p_2,\dots, p_n\)。

构造一个 \(n\) 个点的完全无向图,节点编号分别是 \(1, 2,\dots, n\) 。

节点 i 和节点 j 之间的边边权为 \(|pi − pj| ×|i − j|\),其中 \(|x\) 表示 \(x\) 的绝对值。

请问这个完全图的最小生成树的所有边的权值和是多少?

\(n\leq 5\times 10^4\)。

易发现边的长度都不大于 \(n\),考虑记录一个点连向其他点的边中长度小于 \(n\) 的边。

对于 \(i\) 来说,这些点的满足以下之一:

  • 距离在 \(\sqrt n\) 以内,即 \(|i-j|\leq \sqrt n\)。
  • 大小在 \(\sqrt n\),即 \(|p_i-p_j| \leq \sqrt n\)。

把这些点枚举出来,桶排后使用 \(Kruskal\) 求解。

瓶颈在 \(Kruskal\) 的并查集,时间复杂度 \(O(n\sqrt n\alpha)\)。

当然由于 \(Prim\) 的优先队列跑不满,所以说时间复杂度 \(O(n\sqrt n\log n)\) \(Prim\) 也可以通过本题。

#include<bits/stdc++.h>
using namespace std; #define ll long long
#define pii pair<int,int>
#define fi first
#define se second const int maxn=5e4+5,maxB=255; ll ans; int n,B;
int p[maxn],pid[maxn],dis[maxn]; bool vis[maxn]; priority_queue<pii,vector<pii>,greater<pii>>que; int tmp=1e9,id=0;
inline void check(int u)
{
tmp=1e9,id=0;
for(int i=1;i<=n;i++)
if(i!=u)
{
if(1ll*tmp>1ll*abs(u-i)*abs(p[u]-p[i])) tmp=1ll*abs(u-i)*abs(p[u]-p[i]),id=i;
}
} int main()
{
freopen("ex_pmst2.in","r",stdin);
// freopen("pmst.in","r",stdin);
freopen("pmst.out","w",stdout);
check(1);
scanf("%d",&n);
B=sqrt(n);
for(int i=1;i<=n;i++) scanf("%d",&p[i]),pid[p[i]]=i,dis[i]=n+1;
dis[1]=0;que.push({0,1});
int cnt=0;
while(cnt<n)
{
int u=que.top().se;que.pop();
if(vis[u]) continue;
ans+=dis[u];vis[u]=true;cnt++;
for(int j=max(u-B,1);j<=min(u+B,n);j++)
{
if(dis[j]>abs(u-j)*abs(p[u]-p[j]))
{
dis[j]=abs(u-j)*abs(p[u]-p[j]);
que.push({dis[j],j});
}
}
for(int j=max(p[u]-B,1);j<=min(p[u]+B,n);j++)
{
if(dis[pid[j]]>abs(u-pid[j])*abs(p[u]-j))
{
dis[pid[j]]=abs(u-pid[j])*abs(p[u]-j);
que.push({dis[pid[j]],pid[j]});
}
}
}
printf("%lld",ans);
// cerr<<clock()/1000;
}

卡牌游戏

形式化的,求:

\[\sum_{i=1}^{n}\sum_{k=0}^{m-1} [A_i>B_{i+k\times n \mod m}]
\]

其中若 \(i+k\times n\equiv 0 \mod m\),则小于号右边为 \(B_m\)。

打表发现对于一个 \(i\) 而言 \(i+k\times n \mod m\) 会形成循环节,不同的循环节之间没有交集;循环节的长度等于 \(\gcd(n,m)\),或者说循环节一定完整;不同的 \(i\) 循环节会重复。

8 12
1:
1 9 5 1 9 5 1 9 5 1 9 5
2:
2 10 6 2 10 6 2 10 6 2 10 6
3:
3 11 7 3 11 7 3 11 7 3 11 7
4:
4 0 8 4 0 8 4 0 8 4 0 8
5:
5 1 9 5 1 9 5 1 9 5 1 9
6:
6 2 10 6 2 10 6 2 10 6 2 10
7:
7 3 11 7 3 11 7 3 11 7 3 11
8:
8 4 0 8 4 0 8 4 0 8 4 0

暴力跑出循环节,对于 \(A\) 中的每一个元素,在循环节上查询比自己小的数的个数,然后乘循环次数即可。

对于剩下两个答案同理,是 easy 的。

然而场上没开 long long 导致溢出了(悲。

#include<bits/stdc++.h>
using namespace std; #define ll long long const int maxn=2e5+5; bool swp; int col,n,m;
int a[maxn],b[maxn],tc[maxn],vis[maxn]; ll ans1,ans2,ans3; vector<int>vec[maxn],vect[maxn]; struct treearray
{
#define N 200000
int ts[maxn];
inline int lowbit(int x) {return x&(-x);}
inline void updata(int x,int y) {for(;x<=N;x+=lowbit(x)) ts[x]+=y;}
inline int getsum(int x) {int sum=0;for(;x;x-=lowbit(x)) sum+=ts[x];return sum;}
}T; map<int,int>mp; int main()
{
// freopen("ex_cardgame2.in","r",stdin);
freopen("cardgame.in","r",stdin);
freopen("cardgame.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=m;i++) scanf("%d",&b[i]);
if(n>m) swap(n,m),swap(a,b),swp=1;
for(int i=1;i<=n;i++)
{
int flg=1;
for(int k=0;k<=m;k++)
{
int v=(i+1ll*k*n)%m;
if(v==0) v=m;
if(vis[v]) {tc[i]=vis[v];break;}
col+=flg;flg=0;
vis[v]=col;vec[col].emplace_back(v);
}
vect[tc[i]].emplace_back(i);
}
for(int i=1;i<=n;i++) mp[a[i]]=1;
for(int i=1;i<=m;i++) mp[b[i]]=1;
auto it1=mp.begin(),it2=mp.begin();
for(it2++;it2!=mp.end();it1++,it2++) it2->second+=it1->second;
for(int i=1;i<=m;i++) b[i]=mp[b[i]];
for(int i=1;i<=n;i++) a[i]=mp[a[i]];
for(int i=1;i<=col;i++)
{
for(auto v:vec[i])
{
if(b[v]==0)
{
b[v]=0;
}
T.updata(b[v],1);
}
for(auto v:vect[i])
{
ans1+=1ll*T.getsum(a[v]-1)*(m/vec[i].size());
ans3+=1ll*(T.getsum(N)-T.getsum(a[v]))*(m/vec[i].size());
}
for(auto v:vec[i]) T.updata(b[v],-1);
}
ans2=1ll*n*m-ans1-ans3;
if(swp) swap(ans1,ans3);
printf("%lld\n%lld\n%lld",ans1,ans3,ans2);
}

比特跳跃

探求位运算性质的好题,就是我不会做。

分类讨论:

1.\(s=1\)。

对于所有最高位不为 \(1\) 的,都可以与最高位 \(1\) 其他位为 \(0\) 的数 \(\&\) 得到 \(0\)。对于剩下最高位为 \(1\) 的数,按位取反后不为 \(0\),答案为 \(0\),否则为 \(k\) 和连向其的边中区较小值。

2.\(s=2\)。

将每个点与有一位是不一样的点连边,跑最短路即可。

3.\(s=3\)。

先跑一次最短路,每个点 \(x\) 递推的求出满足 \(x|y=x\) 的最小的 \(dis_y\),然后判断是否有 \(dis_x>dis_y+x\times k\),如果有就令 \(dis_x=dis_y+x\times k\)。

再跑一次最短路即可求得答案。

// ubsan: undefined
// accoders
#include<bits/stdc++.h>
using namespace std; #define int long long
#define ll long long
#define pli pair<ll,int>
#define fi first
#define se second const int maxn=2e6+5; int n,m,s,k;
int f[maxn]; struct Edge
{
int tot;
int head[maxn];
struct edgenode{int to,nxt;ll w;}edge[maxn*2];
inline void add(int x,int y,ll w)
{
tot++;
edge[tot].to=y;
edge[tot].w=w;
edge[tot].nxt=head[x];
head[x]=tot;
}
}G; priority_queue<pli,vector<pli>,greater<pli>>que;
ll dis[maxn];
bool vis[maxn]; int flg=0; inline void dij()
{
if(!flg) memset(dis,0x3f,sizeof(dis));
else for(int i=2;i<=n;i++) que.push({dis[i],i});
flg++;
memset(vis,0,sizeof(vis));
dis[1]=0;que.push({0,1});
while(!que.empty())
{
int u=que.top().se;que.pop();
if(vis[u]) continue;
vis[u]=true;
for(int i=G.head[u];i;i=G.edge[i].nxt)
{
int w=G.edge[i].w,v=G.edge[i].to;
if(dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
que.push({dis[v],v});
}
}
}
} signed main()
{
freopen("jump.in","r",stdin);
freopen("jump.out","w",stdout);
scanf("%lld%lld%lld%lld",&n,&m,&s,&k);
for(int i=1,u,v,w;i<=m;i++) scanf("%lld%lld%lld",&u,&v,&w),G.add(u,v,w),G.add(v,u,w);
if(s==1)
{
for(int i=2;i<n;i++) printf("0 ");
bool flg=0;
for(int i=1;i<=20;i++) flg|=(n==((1<<i)-1));
if(!flg) printf("0");
else
{
ll ans=k;
for(int i=G.head[n];i;i=G.edge[i].nxt) ans=min(ans,G.edge[i].w);
printf("%lld ",ans);
}
}
else if(s==2)
{
for(int i=1;i<=n;i++)
{
for(int j=0;j<=20&&(n>>j);j++)
{
int st=i^(1<<j);
if(st<=n) G.add(i,st,1ll*k*(1<<j)),G.add(st,i,1ll*k*(1<<j));
}
}
dij();
for(int i=2;i<=n;i++) printf("%lld ",dis[i]);
}
else
{
for(int i=2;i<=n;i++) G.add(1,i,(1|i)*k);
dij();
for(int i=1;i<=n;i++) f[i]=i;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=20;j++)
{
if((i>>j)&1)
{
if(dis[f[i]]>dis[f[i^(1<<j)]]) f[i]=f[i^(1<<j)];
}
}
dis[i]=min(dis[f[i]]+1ll*i*k,dis[i]);
}
dij();
for(int i=2;i<=n;i++) printf("%lld ",dis[i]);
}
}

区间

固定二元组的右端点 \(r\),找到一个最小的 \(l\) 使得二元组 \((l,r)\) 满足条件 \(2\)。

观察 \((l,r)\) 中满足条件 \(1\) 的左端点,发现这些点是一个从 \(l\) 开始的单调递减的单调栈中小于 \(B_r\) 的部分。

假设所有的查询的 \(L_i=1\),离线完询问后枚举二元组右端点,同时维护单调栈,每次二分查询单调栈里有多少点小于 \(B_r\) 即可。

可是 \(L_i\) 并不全部等于一,那么我们设 \(val_i\) 表示 \(i\) 这个点可以作为多少个二元组中的左端点出现,每次二分查询时,给栈内小于 \(B_r\) 的部分的 \(val_i\) 加一,每次查询 \([L_i,R_i]\) 的 \(val\) 的和即可。

由于单调栈内的节点编号并不会连续,如果暴力实现 \(val\) 值的更改显然不合适,那么我们把栈内的 \(val\) 值附上新的编号,维护在线段树上,如果这个点被栈弹出了,那么他的 \(val\) 值存在本身编号的位置。

由于栈内的原编号是递增的,在 \(R_i\) 时求出栈内原编号大于 \(L_i\) 点的 \(val\) 值和,以及弹出栈的 \([L_i,R_i]\) 的 \(val\) 值和。

场上手残了,树状数组写挂了。

// ubsan: undefined
// accoders
#include<bits/stdc++.h>
using namespace std; #define ll long long const int maxn=3e5+5; int n,m;
int a[maxn],b[maxn],l[maxn],r[maxn],flg[maxn]; vector<int>vec[maxn]; ll ans[maxn]; struct treearray
{
#define N 300000
ll ts[maxn];
inline int lowbit(int x) {return x&(-x);}
inline void updata(int x,int y) {for(;x<=N;x+=lowbit(x)) ts[x]+=y;}
inline ll getsum(int x) {ll sum=0;for(;x;x-=lowbit(x)) sum+=ts[x];return sum;}
}Ta; namespace linetree
{
#define lch(p) p*2
#define rch(p) p*2+1
struct treenode{ll sum,lz;}tr[maxn*12];
inline void updata(int p){tr[p].sum=tr[lch(p)].sum+tr[rch(p)].sum;}
inline void push_down(int p,int l,int r)
{
if(!tr[p].lz||l==r) return ;
int mid=(l+r)>>1;
tr[lch(p)].sum+=tr[p].lz*(mid-l+1),tr[lch(p)].lz+=tr[p].lz;
tr[rch(p)].sum+=tr[p].lz*(r-mid),tr[rch(p)].lz+=tr[p].lz;
tr[p].lz=0;
}
inline void insert(int p,int l,int r,int lx,int rx,int v)
{
if(r<lx||l>rx) return ;
if(lx<=l&&r<=rx)
{
tr[p].sum+=(r-l+1)*v;
tr[p].lz+=v;
return ;
}
push_down(p,l,r);
int mid=(l+r)>>1;
insert(lch(p),l,mid,lx,rx,v),insert(rch(p),mid+1,r,lx,rx,v);
updata(p);
}
inline ll qry(int p,int l,int r,int lx,int rx)
{
if(r<lx||l>rx) return 0;
if(lx<=l&&r<=rx) return tr[p].sum;
push_down(p,l,r);
int mid=(l+r)>>1;
return qry(lch(p),l,mid,lx,rx)+qry(rch(p),mid+1,r,lx,rx);
}
} int tp;
int stk[maxn]; inline int fr(int x)
{
int l=1,r=tp,ans=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(a[stk[mid]]<x) ans=mid,r=mid-1;
else l=mid+1;
}
return ans;
}
inline int fr_id(int x)
{
int l=1,r=tp,ans=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(stk[mid]>=x) ans=mid,r=mid-1;
else l=mid+1;
}
return ans;
} int main()
{
// freopen("ex_interval2.in","r",stdin);
freopen("interval.in","r",stdin);
freopen("interval.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=2;i<=n;i++) scanf("%d",&b[i]);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&l[i],&r[i]);
vec[r[i]].push_back(i);
}
stk[++tp]=1;
for(int i=2;i<=n;i++)
{
int tmp=fr(b[i]);
if(tmp)
{
linetree::insert(1,1,n,tmp,tp,1);
}
for(auto v:vec[i])
{
tmp=fr_id(l[v]);
ans[v]=(Ta.getsum(r[v])-Ta.getsum(l[v]-1));
if(tmp) ans[v]+=linetree::qry(1,1,n,tmp,tp);
}
while(tp&&a[stk[tp]]<=a[i])
{
ll val=linetree::qry(1,1,n,tp,tp);
Ta.updata(stk[tp],val);
linetree::insert(1,1,n,tp,tp,-val);
tp--;
}
stk[++tp]=i;
}
for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
}

多校A层冲刺NOIP2024模拟赛09的更多相关文章

  1. 多校B层冲刺NOIP20211111模拟12

    题面:PDFhttp://xn--gwt928b.accoders.com/pdf/10248/10248.pdfhttp://xn--gwt928b.accoders.com/pdf/10248/1 ...

  2. 【CJOJ P1957】【NOIP2010冲刺十模拟赛】数字积木

    [NOIP2010冲刺十模拟赛]数字积木 Description 小明有一款新式积木,每个积木上都有一个数,一天小明突发奇想,要是把所有的积木排成一排,所形成的数目最大是多少呢? 你的任务就是读入n个 ...

  3. 冲刺Noip2017模拟赛7 解题报告——五十岚芒果酱

    1.二叉树(binary) .二叉树 (binary.cpp/c/pas) [问题描述] 二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: ()若左子树不空,则左子树上所有结点的值均小于它的根结 ...

  4. 冲刺Noip2017模拟赛8 解题报告——五十岚芒果酱

    1.鼎纹 [问题描述] 据说鼎纹的 种制造 式是 铜模印出来的,这是我国古代劳动 智慧 的结晶.铜模印过的地 ,会留下深深的印记,经过时间的炼化,洗 练成历史的遗存. 聪明的古代劳动人民拥有一个 a ...

  5. 冲刺Noip2017模拟赛4 解题报告——五十岚芒果酱

    题1 韬韬抢苹果(apple) [问题描述] 又到了收获的季节,树上结了许多韬韬,错了,是许多苹果,有很多个小韬韬都来摘苹 果.每个韬韬都想要最大的苹果,所以发生了争执,为了解决他们的矛盾,出题人定了 ...

  6. 冲刺Noip2017模拟赛2 解题报告——五十岚芒果酱

    题1 牛跑步(running) [题目描述] 新牛到部队,CG 要求它们每天早上搞晨跑,从 A 农场跑到 B 农场.从 A 农场到 B 农场中有 n- 个路口,分别标上号,A 农场为 号,B 农场为 ...

  7. 冲刺Noip2017模拟赛1 解题报告——五十岚芒果酱

    题1 国际象棋(chess) [问题描述] 有N个人要参加国际象棋比赛,该比赛要进行K场对弈.每个人最多参加2场对弈,最少参加0场对弈.每个人都有一个与其他人都不相同的等级(用一个正整数来表示).在对 ...

  8. 冲刺Noip2017模拟赛6 解题报告——五十岚芒果酱

    1.ksum(ksum) [问题描述] Peter喜欢玩数组.NOIP这天,他从Jason手里得到了大小为n的一个正整数 数组. Peter求出了这个数组的所有子段和,并将这n(n+)/2个数降序排序 ...

  9. 冲刺Noip2017模拟赛5 解题报告——五十岚芒果酱

    1. 公约数(gcd) [问题描述] 给定一个正整数,在[,n]的范围内,求出有多少个无序数对(a,b)满足 gcd(a,b)=a xor b. [输入格式] 输入共一行,一个正整数n. [输出格式] ...

  10. 冲刺Noip2017模拟赛3 解题报告——五十岚芒果酱

    题1  素数 [问题描述] 给定一个正整数N,询问1到N中有多少个素数. [输入格式]primenum.in 一个正整数N. [输出格式]primenum.out 一个数Ans,表示1到N中有多少个素 ...

随机推荐

  1. Go 接收命令行参数

    在 Go 语言中,可以使用标准库中的 os 包和 flag 包来接收和处理命令行参数. 使用 os 包 os.Args 是一个字符串切片,其中第一个元素是程序的名称,后续元素是传递给程序的命令行参数. ...

  2. uni-app 商场样式

    基于ColorUI-UniApp css样式开发的商城基础模 模板基础功能实现 1.首页今日推荐 点击 会商品加一 2.分类 页面 左右列表联动 3.购物车 商品加减 4.我的 订单管理  账号密码登 ...

  3. android 访问域名接口报错

    1. 移动端访问https域名及接口,显示 java.net.UnknownHostException: Unable to resolve host "xxx" : No add ...

  4. 一文了解JSON

    目录 JSON 在JavaScript 中的使用. json 的定义 json 的访问 json 的两个常用方法 JSON 在 在 java 中的使用 javaBean 和 和 json 的互转 Li ...

  5. ECharts实现雷达图详解

    ECharts 是一款由百度开源的数据可视化工具,它提供了丰富的图表类型,如折线图.柱状图.饼图.散点图.雷达图.地图.K线图.热力图.仪表盘等,以及丰富的交互功能.ECharts 组件的核心功能实现 ...

  6. 公有云-实验一 实践腾讯云部署Web应用

    实验一 实践腾讯云部署Web应用 概述 企业A需要搭建一套在互联网上发布的论坛平台,但是企业内部并没有完善的基础架构设施,难以保证论坛平台的高可用性和高安全性.经过IT部门相关专家分析讨论,决定在腾讯 ...

  7. HTML – Emmet Shortcut

    前言 程序员就爱 hot key, 就爱 shortcut. 当然这里指的是不牺牲安全和结果的情况下用尽可能少的力气去做事情, 而不是那种 shortcut 了以后会翻车的. Emmet 就是专门写 ...

  8. Magic Quadrant 魔力象限

    前言 在做 Web Application Firewall research 的时候看见了一张图. 这格式之前也看见过, 但没怎么上心, 现在才注意到它很好表达了行业或者产品的市场格局. 于是特地 ...

  9. Email 关于 POP3 IMAP SMTP office365 Outlook Gmail G-Suit shared mailbox小小理解

    Outlook 是微软的一个 email 软件, 管理 email 的 UI. Gmail 是 google 的 office365 是一个配套, 里面有 email, one drive, exce ...

  10. 一,初始 MyBatis-Plus

    一,初始 MyBatis-Plus @ 目录 一,初始 MyBatis-Plus 1. MyBatis-Plus 的概述 2. 入门配置第一个 MyBatis-Plus 案例 3. 补充说明: 3.1 ...