7.22考试总结(NOIP模拟23)[联·赛·题]
不拼尽全力去试一下,又怎么会知道啊
前言
又是被细节问题搞掉的一天。
T1 的话,与正解相差无几,少打了两个 else 一个 ls 打成了 rs,然后就爆零了(本来还有 45pts 的),然后加了一个离散化就 A 了(我裂开)
T2 是写了一个贪心,虽然正确性无法保证,但是个别东西打错了,然后在最后几分钟的时候疯狂的改,结果分数越改越少。
答题的时候发现了一个比较好的打法:每次先开最难的题,打出暴力就走人,然后再去搞别的题。
T1 联
解题思路
线段树裸题,实现上注意一下操作的优先级,以及 if 语句后的 else
显然的,1 和 2 操作对于以前的操作是可以直接覆盖的。
3 操作可以将 1 和 2 操作进行对掉。
同时,对于 \(xor\) 的性质而言,两个 3 操作可以相互抵消。
然后就是区间修改以及区间查询了,注意 laz 标记的下放。
虽然,n的范围是 \(10^{18}\) 但是操作数量是非常有限的。
因此可以离散化,对于每一个边界以及边界的前或者后一个数,以及 1 都要进行离散化,毕竟有用的节点不只是边界。。
code
#include<bits/stdc++.h>
#define int long long
#define ls x<<1
#define rs x<<1|1
#define f() cout<<"Pass"<<endl;
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=7e5+110,INF=1e18;
int m,n,tre1[N<<2],tre2[N<<2],laz[N<<2];
int cnt,lsh[N];
struct Ques
{
int opt,l,r;
}q[N];
void push_up(int x)
{
tre1[x]=min(tre1[ls],tre1[rs]);
tre2[x]=min(tre2[ls],tre2[rs]);
}
void build(int x,int l,int r)
{
if(l==r)
{
tre1[x]=l;
tre2[x]=INF;
return ;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
push_up(x);
}
void push_down(int x,int l,int r)
{
if(!laz[x]) return ;
int mid=(l+r)>>1;
if(laz[x]==1)
{
tre1[ls]=tre1[rs]=INF;
tre2[ls]=l;
tre2[rs]=mid+1;
laz[ls]=laz[rs]=1;
laz[x]=0;
return ;
}
if(laz[x]==2)
{
tre2[ls]=tre2[rs]=INF;
tre1[ls]=l;
tre1[rs]=mid+1;
laz[ls]=laz[rs]=2;
laz[x]=0;
return ;
}
if(laz[ls])
{
if(laz[ls]==1)
{
swap(tre1[ls],tre2[ls]);
laz[ls]=2;
}
else if(laz[ls]==2)
{
swap(tre1[ls],tre2[ls]);
laz[ls]=1;
}
else
{
swap(tre1[ls],tre2[ls]);
laz[ls]=0;
}
}
else
{
swap(tre1[ls],tre2[ls]);
laz[ls]=3;
}
if(laz[rs])
{
if(laz[rs]==1)
{
swap(tre1[rs],tre2[rs]);
laz[rs]=2;
}
else if(laz[rs]==2)
{
swap(tre1[rs],tre2[rs]);
laz[rs]=1;
}
else
{
swap(tre1[rs],tre2[rs]);
laz[rs]=0;
}
}
else
{
swap(tre1[rs],tre2[rs]);
laz[rs]=3;
}
laz[x]=0;
}
void update1(int x,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
{
tre1[x]=INF;
tre2[x]=l;
laz[x]=1;
return ;
}
push_down(x,l,r);
int mid=(l+r)>>1;
if(L<=mid) update1(ls,l,mid,L,R);
if(R>mid) update1(rs,mid+1,r,L,R);
push_up(x);
}
void update2(int x,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
{
tre1[x]=l;
tre2[x]=INF;
laz[x]=2;
return ;
}
push_down(x,l,r);
int mid=(l+r)>>1;
if(L<=mid) update2(ls,l,mid,L,R);
if(R>mid) update2(rs,mid+1,r,L,R);
push_up(x);
}
void update3(int x,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
{
if(!laz[x])
{
swap(tre1[x],tre2[x]);
laz[x]=3;
}
else if(laz[x]==1)
{
tre1[x]=l;
tre2[x]=INF;
laz[x]=2;
}
else if(laz[x]==2)
{
tre2[x]=l;
tre1[x]=INF;
laz[x]=1;
}
else
{
swap(tre1[x],tre2[x]);
laz[x]=0;
}
return ;
}
push_down(x,l,r);
int mid=(l+r)>>1;
if(L<=mid) update3(ls,l,mid,L,R);
if(R>mid) update3(rs,mid+1,r,L,R);
push_up(x);
}
void solve()
{
build(1,1,n);
for(int i=1;i<=m;i++)
{
if(q[i].opt==1) update1(1,1,n,q[i].l,q[i].r);
else if(q[i].opt==2) update2(1,1,n,q[i].l,q[i].r);
else if(q[i].opt==3) update3(1,1,n,q[i].l,q[i].r);
printf("%lld\n",lsh[tre1[1]]);
}
}
signed main()
{
m=read();
for(int i=1;i<=m;i++)
{
q[i].opt=read();
q[i].l=read();
q[i].r=read();
lsh[++n]=q[i].l;
lsh[++n]=q[i].r;
lsh[++n]=q[i].l+1;
lsh[++n]=q[i].r+1;
}
lsh[++n]=1;
sort(lsh+1,lsh+n+1);
n=unique(lsh+1,lsh+n+1)-lsh-1;
for(int i=1;i<=m;i++)
{
q[i].l=lower_bound(lsh+1,lsh+n+1,q[i].l)-lsh;
q[i].r=lower_bound(lsh+1,lsh+n+1,q[i].r)-lsh;
}
solve();
return 0;
}
T2 赛
解题思路
首先说明一下贪心做法是错误的,毕竟对于每一种情况我们无法保证选的满足两个人需要的最多就是最优的。
但是可以骗到 70pts
贪心不行,那就暴力枚举呗。
对于所有的物品,我们分为四大类:
两个人都喜欢的
第一个人喜欢但是第二个人不喜欢的
第二个人喜欢但是第一个人不喜欢的
其它的
我们可以暴力枚举第一类物品的数量,然后对应修改选的第二三类物品的数量。
然后在第四类物品中选择最小的若干个。
对于最小的前几个数可以用动态开点(好像不开也可以)权值线段树来维护。
代码实现细节比较多。。
当然这个题也可以在暴力的基础上三分法搞。
code
70pts的贪心
#include<bits/stdc++.h>
#define int long long
#define ls x<<1
#define rs x<<1|1
#define f() cout<<"Pass"<<endl;
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=5e5+10;
int n,m,k,ans,pos,s[N];
int cnt1,cnt2,q1[N],q2[N];
int top,sta[N],res[N];
int t1,t2,s1[N],s2[N];
bool vis[N];
vector<int> v;
bool comp(int x,int y)
{
return s[x]<s[y];
}
signed main()
{
n=read();
m=read();
k=read();
for(int i=1;i<=n;i++)
s[i]=read();
cnt1=read();
for(int i=1;i<=cnt1;i++)
{
q1[i]=read();
vis[q1[i]]=true;
}
cnt2=read();
for(int i=1;i<=cnt2;i++)
{
q2[i]=read();
if(vis[q2[i]]) v.push_back(q2[i]);
else vis[q2[i]]=true;
}
if(k>cnt1||k>cnt2)
{
printf("-1");
return 0;
}
memset(vis,false,sizeof(vis));
for(int i=0;i<v.size();i++)
sta[++top]=v[i];
vector<int>().swap(v);
sort(sta+1,sta+top+1,comp);
for(int i=1;i<=top;i++)
vis[sta[i]]=true;
for(int i=1;i<=cnt1;i++)
if(!vis[q1[i]])
s1[++t1]=q1[i];
for(int i=1;i<=cnt2;i++)
if(!vis[q2[i]])
s2[++t2]=q2[i];
memset(vis,false,sizeof(vis));
sort(s1+1,s1+t1+1,comp);
sort(s2+1,s2+t2+1,comp);
for(pos=1;pos<=2*k-m;pos++)
ans+=s[sta[pos]],vis[sta[pos]]=true;
int pre=pos;
int temp=k-pos+1;
int pos1=1,pos2=1;
if(2*temp>m||pos>top+1)
{
cout<<-1;
return 0;
}
for(int i=1;i<=temp;i++)
{
if(pos==top+1&&pos1==cnt1+1)
{
cout<<-1;
return 0;
}
if(pos==top+1)
{
vis[s1[pos1]]=true;
ans+=s[s1[pos1]];
pos1++;
continue;
}
if(s[sta[pos]]<=s[s1[pos1]])
{
vis[sta[pos]]=true;
ans+=s[sta[pos]];
pos++;
continue;
}
vis[s1[pos1]]=true;
ans+=s[s1[pos1]];
pos1++;
}
for(int i=pos-pre+1;i<=temp;i++)
{
if(pos==top+1&&pos2==cnt2+1)
{
cout<<-1;
return 0;
}
if(pos==top+1)
{
vis[s2[pos2]]=true;
ans+=s[s2[pos2]];
pos2++;
continue;
}
if(s[sta[pos]]<=s[s2[pos2]])
{
vis[sta[pos]]=true;
ans+=s[sta[pos]];
pos++;
continue;
}
vis[s2[pos2]]=true;
ans+=s[s2[pos2]];
pos2++;
}
int cnt=0;
for(int i=1;i<=n;i++)
if(!vis[i])
res[++cnt]=i;
sort(res+1,res+cnt+1,comp);
if(cnt<m-pos1-pos2-pos+3)
{
cout<<-1;
return 0;
}
for(int i=1;i<=m-pos1-pos2-pos+3;i++)
ans+=s[res[i]];
printf("%lld",ans);
return 0;
}
正解
#include<bits/stdc++.h>
#define int long long
#define ls tre[x].l
#define rs tre[x].r
#define f() cout<<"Pass"<<endl;
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=5e5+10,INF=1e18;
int n,m,k,ans,pos,tot,root,s[N];
int cnt1,cnt2,q1[N],q2[N];
int top,cnt,lsh[N],sta[N];
int t1,t2,t3,s3[N],s1[N],s2[N];
bool vis[N];
vector<int> v;
bool comp(int x,int y)
{
return s[x]<s[y];
}
struct VOP_Segment_Tree
{
int l,r,siz,dat;
}tre[N*80];
void push_up(int x)
{
tre[x].dat=tre[ls].dat+tre[rs].dat;
tre[x].siz=tre[ls].siz+tre[rs].siz;
}
void insert(int &x,int l,int r,int pos,int val)
{
if(!x) x=++tot;
if(l==r)
{
tre[x].dat+=val*lsh[l];
tre[x].siz+=val;
return ;
}
int mid=(l+r)>>1;
if(pos<=mid) insert(ls,l,mid,pos,val);
else insert(rs,mid+1,r,pos,val);
push_up(x);
}
int query(int x,int l,int r,int rk)
{
if(rk<=0) return 0;
if(l==r) return tre[x].dat;
int mid=(l+r)>>1;
if(rk<=tre[ls].siz) return query(ls,l,mid,rk);
return tre[ls].dat+query(rs,mid+1,r,rk-tre[ls].siz);
}
signed main()
{
n=read();
m=read();
k=read();
for(int i=1;i<=n;i++)
lsh[i]=s[i]=read();
cnt1=read();
for(int i=1;i<=cnt1;i++)
{
q1[i]=read();
vis[q1[i]]=true;
}
cnt2=read();
for(int i=1;i<=cnt2;i++)
{
q2[i]=read();
if(vis[q2[i]]) sta[++top]=q2[i];
else vis[q2[i]]=true;
}
if(cnt1<k||cnt2<k||top<2*k-m)
{
cout<<-1;
return 0;
}
sort(sta+1,sta+top+1,comp);
sort(lsh+1,lsh+n+1);
cnt=unique(lsh+1,lsh+n+1)-lsh-1;
for(int i=1;i<=n;i++)
s[i]=lower_bound(lsh+1,lsh+cnt+1,s[i])-lsh;
memset(vis,false,sizeof(vis));
top=min(top,m);
for(int i=1;i<=top;i++)
vis[sta[i]]=true;
for(int i=1;i<=cnt1;i++)
if(!vis[q1[i]]) s1[++t1]=q1[i],vis[q1[i]]=true;
for(int i=1;i<=cnt2;i++)
if(!vis[q2[i]]) s2[++t2]=q2[i],vis[q2[i]]=true;
sort(s1+1,s1+t1+1,comp);
sort(s2+1,s2+t2+1,comp);
for(int i=1;i<=top;i++)
ans+=lsh[s[sta[i]]];
for(int i=1;i<=k-top;i++)
ans+=lsh[s[s1[i]]]+lsh[s[s2[i]]];
for(int i=k-top+1;i<=t1;i++)
vis[s1[i]]=false;
for(int i=k-top+1;i<=t2;i++)
vis[s2[i]]=false;
for(int i=1;i<=n;i++)
if(!vis[i])
insert(root,1,cnt,s[i],1);
int sum=ans;
ans+=query(1,1,cnt,m-2*k+top);
for(int i=top-1;i>=0;i--)
{
if(i<2*k-m) break;
if(k-i>cnt1||k-i>cnt2) break;
sum-=lsh[s[sta[i+1]]];
insert(root,1,cnt,s[sta[i+1]],1);
if(k-i<1) continue;
sum+=lsh[s[s1[k-i]]]+lsh[s[s2[k-i]]];
insert(root,1,cnt,s[s1[k-i]],-1);
insert(root,1,cnt,s[s2[k-i]],-1);
ans=min(ans,sum+query(1,1,cnt,m-2*k+i));
}
printf("%lld",ans);
return 0;
}
T3 题
解题思路
非常妙的一个题。。。
首先,每个人挑选的顺序不同,答案是不同的。
正着枚举不是特别好判断两者是否能共存,因此我们选择逆推。
对于每两个不能同时存在的状态,是可以递推到这两个节点和其它节点的。
类似于路径压缩一类的东西。
对于三者之间的共存关系,因为是逆推,如果当前扫到的“边”的两个连接点
如果两个点与现在扫到的节点都不可以共存,那么显然这个节点是无法存活到最后的。
如果当前连边的两个节点中有一个节点是无法与当前扫到节点共存的话,那么另一个节点也不可以。
最后对于答案统计的时候需要用到集合之间的交集,可以用 bitset 维护。
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=410,M=5e4+10;
int n,m,ans;
bitset<N> f,g[N];
struct Node
{
int x,y;
void insert()
{
x=read();
y=read();
}
}s[M];
signed main()
{
n=read();
m=read();
for(int i=1;i<=m;i++)
s[i].insert();
for(int i=1;i<=n;i++)
{
g[i][i]=true;
for(int j=m;j>=1;j--)
{
if(g[i][s[j].x]&&g[i][s[j].y])
{
f[i]=true;
break;
}
if(g[i][s[j].x]||g[i][s[j].y])
g[i][s[j].x]=g[i][s[j].y]=true;
}
}
for(int i=1;i<=n;i++)
if(!f[i])
for(int j=1;j<i;j++)
if(!f[j]&&!(g[i]&g[j]).count())
ans++;
printf("%lld",ans);
return 0;
}
7.22考试总结(NOIP模拟23)[联·赛·题]的更多相关文章
- noip模拟23[联·赛·题]
\(noip模拟23\;solutions\) 怎么说呢??这个考试考得是非常的惨烈,一共拿了70分,为啥呢 因为我第一题和第三题爆零了,然后第二题拿到了70分,还是贪心的分数 第一题和第二题我调了好 ...
- 5.22考试总结(NOIP模拟1)
5.22考试总结(NOIP模拟1) 改题记录 T1 序列 题解 暴力思路很好想,分数也很好想\(QAQ\) (反正我只拿了5pts) 正解的话: 先用欧拉筛把1-n的素数筛出来 void get_Pr ...
- [考试总结]noip模拟23
因为考试过多,所以学校的博客就暂时咕掉了,放到家里来写 不过话说,vscode的markdown编辑器还是真的很好用 先把 \(noip\) 模拟 \(23\) 的总结写了吧.. 俗话说:" ...
- 2021.9.22考试总结[NOIP模拟59]
T1 柱状图 关于每个点可以作出两条斜率绝对值为\(1\)的直线. 将绝对值拆开,对在\(i\)左边的点\(j\),\(h_i-i=h_j-j\),右边则是把减号换成加号. 把每个点位置为横坐标,高度 ...
- NOIP 模拟 $23\; \rm 赛$
题解 将所有物品分成四类,分别为两人共同喜欢的,只有一人喜欢的,没人喜欢的. 首先,先从两人共同喜欢的物品里找出 \(k\) 个,这时,就要从剩余的找出 \(\rm m-k\) 个,而且是最小的. 用 ...
- 5.23考试总结(NOIP模拟2)
5.23考试总结(NOIP模拟2) 洛谷题单 看第一题第一眼,不好打呀;看第一题样例又一眼,诶,我直接一手小阶乘走人 然后就急忙去干T2T3了 后来考完一看,只有\(T1\)骗到了\(15pts\)[ ...
- 6.17考试总结(NOIP模拟8)[星际旅行·砍树·超级树·求和]
6.17考试总结(NOIP模拟8) 背景 考得不咋样,有一个非常遗憾的地方:最后一题少取膜了,\(100pts->40pts\),改了这么多年的错还是头一回看见以下的情景... T1星际旅行 前 ...
- 20165237 2017-2018-2 《Java程序设计》第四周考试补做及2-3章编程题
20165237 2017-2018-2 <Java程序设计>第四周考试补做及2-3章编程题 测试JDB: 用JDB调试上一个程序,输入1.2.3: 2-3章编程题代码托管 (程序的运行结 ...
- 2021.9.17考试总结[NOIP模拟55]
有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...
- 2021.7.29考试总结[NOIP模拟27]
T1 牛半仙的妹子图 做法挺多的,可以最小生成树或者最短路,复杂度O(cq),c是颜色数. 我考场上想到了原来做过的一道题影子,就用了并查集,把边权排序后一个个插入,记录权值的前缀和,复杂度mlogm ...
随机推荐
- python 远程windows系统执行cmd命令
如果你的服务器是windows系统,不想一台一台mstsc远程到桌面上去操作,python是有模块可以远程处理的:winrm pip install pywinrm 安装模块即可 windows系统服 ...
- 前端之多线程 ---webworker
一.啥是workerJavaScript为单线程,worker则为JavaScript创建多线程环境.使用场景如:计算文件hash,计算大于1G的文件hash过程是很慢的,但由于要将hash传给后端, ...
- 跨域是什么?Vue项目中你是如何解决跨域的呢?
一.跨域是什么 跨域本质是浏览器基于同源策略的一种安全手段 同源策略(Sameoriginpolicy),是一种约定,它是浏览器最核心也最基本的安全功能 所谓同源(即指在同一个域)具有以下三个相同点 ...
- Oracle SQL 创建一个简单的存储过程procedure
Oracle 简单的创建一个存储过程procedure 如果学过别的语言,例如java,c这些,那么其实很好理解,其实就是面向数据库的操作 简单的例子如下: --创建或者重写存储过程 create o ...
- 力扣620(MySQL)-有趣的电影(简单)
题目: 某城市开了一家新的电影院,吸引了很多人过来看电影.该电影院特别注意用户体验,专门有个 LED显示板做电影推荐,上面公布着影评和相关电影描述. 作为该电影院的信息部主管,您需要编写一个 SQL查 ...
- 力扣551(java)-学生出勤记录Ⅰ(简单)
题目: 给你一个字符串 s 表示一个学生的出勤记录,其中的每个字符用来标记当天的出勤情况(缺勤.迟到.到场).记录中只含下面三种字符: 'A':Absent,缺勤'L':Late,迟到'P':Pres ...
- 云原生事件驱动引擎(RocketMQ-EventBridge)应用场景与技术解析
简介: RocketMQ 给人最大的印象一直是一个消息引擎.那什么是事件驱动引擎?为什么我们这次要推出事件驱动引擎这个产品?他有哪些应用场景,以及对应的技术方案是什么?本文我们就一起来看下. 作者:罗 ...
- 直播回顾:如何对付臭名昭著的 IO 夯?诊断利器来了 | 龙蜥技术
简介:听到IO夯总是让人头疼,那有没有可以分析IO夯问题的利器? 编者按:sysAK(system analyse kit),是龙蜥社区(OpenAnolis)系统运维 SIG 下面的一个开源项目, ...
- dotnet 如何将 Microsoft.Maui.Graphics 对接到 UNO 框架
本文将和大家介绍如何将 Microsoft.Maui.Graphics 对接到 UNO 框架里面.一旦完成 Microsoft.Maui.Graphics 对接,即可让 UNO 框架复用现有的许多绘制 ...
- dotnet 6 修复在 System.Text.Json 使用 source generation 源代码生成提示 SYSLIB1032 错误
在 dotnet 6 内置了通过源代码生成的方式进行序列化 JSON 对象,性能非常高.使用的时候需要将 Json 序列化工具类换成 dotnet 运行时自带的 System.Text.Json 进行 ...