CSP2024 前集训:NOIP2024加赛 1

news/2024/12/26 1:16:15/文章来源:https://www.cnblogs.com/Charlieljk/p/18528886

前言

image

赛时本来 rk3,赛后自己加 hack 卡自己于是成 rk4 了。

因为这场是假做法大战,T1 假贪心有 \(92pts\);T2 \(O(n^2m)\) 能过(是因为数据里 \(m\le 10\));

T3 相当抽象,赛时我打的爆搜只加了一个剪枝能得 \(70pts\),赛后发现无解的时候会跑满,于是提前判掉无解就过了甚至最优解 \(30ms\),发现数据里的数据生成器好像是错的?\(m\) 全都很小,但是发现 \(m\) 很大的时候基本上直接输出最短路就是答案,所以造一组 \(m\) 不大不小的就卡掉了;

然后我想了一个假做法,刚开始我还以为是真的还上去讲,结果大家全都跟着打假做法和爆搜,经过与 wang54321 等人的分析发现是假的,于是造了好长时间的 hack,刚开始不知道怎么造才能完全掉随机打乱,发现及时随机打乱原来能错的仍有不小的错误率,所以直接多随几组能错的绑包就好了。

然后就有了菜等人数据点分治过 hack(因为 hack 数据不是很大),丁真研发新的假做法继续过 hack,xrlong 发现我的数据有自环(我记得我判了呀不是),遂重造 hack,现在除了正解都死了。

本来以为 T3 已经是假做法巅峰了,结果下午发现 T4 目前没有任何一个人打的是正解……

因为 &&|| 有短路,T4 暴力先判并查集比先判是否有交快得多(因为并查集常数小,而 check 全是 if 常数巨大)。

T1 玩游戏

  • 部分分 \(24pts\)\(O(n^2)\) 区间 DP。

  • 正解:

    贪心,考虑如果移动一次断点不可能只移动到一个更大的位置就停了,只要移一定移到更小的位置,所以可以处理处 next。

    发现跳到最小值位置就停了,考虑再反正跳一遍就好了,跳的过程中判是否能安全走完更大的那部分即可,复杂度 \(O(n)\)

    点击查看代码
    #include<bits/stdc++.h>
    #define ll long long
    #define endl '\n'
    #define sort stable_sort
    using namespace std;
    const int N=1e5+10;
    template<typename Tp> inline void read(Tp&x)
    {x=0;register bool z=true;register char c=getchar_unlocked();for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);x=(z?x:~x+1);
    }
    template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
    template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
    template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
    template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
    int T,n,m,cnt1,cnt2,nxt1[N],nxt2[N]; 
    ll a[N],b[N],c[N],pre[N],suf[N]; bool flag;
    signed main()
    {for(read(T);T;T--,memset(nxt1,0,4*(n+1)),memset(nxt2,0,4*(n+1))){read(n,m); for(int i=1;i<=n;i++) read(c[i]);a[cnt1=1]=0; for(int i=m;i>=2;i--) a[++cnt1]=c[i];b[cnt2=1]=0; for(int i=m+1;i<=n;i++) b[++cnt2]=c[i];for(int i=1;i<=cnt1;i++) pre[i]=pre[i-1]+a[i];for(int i=1;i<=cnt2;i++) suf[i]=suf[i-1]+b[i];if(pre[cnt1]+suf[cnt2]>0) {puts("No"); continue;}for(int i=2,x=1;i<=cnt1;i++) if(pre[i]<pre[x]) nxt1[x]=i,x=i;for(int i=cnt1-1,x=cnt1;i;i--) if(pre[i]<pre[x]) nxt1[x]=i,x=i;for(int i=2,x=1;i<=cnt2;i++) if(suf[i]<suf[x]) nxt2[x]=i,x=i;for(int i=cnt2-1,x=cnt2;i;i--) if(suf[i]<suf[x]) nxt2[x]=i,x=i;for(int x=1,y=1;nxt1[x]||nxt2[y];flag=0){for(int i=x+1;i<=nxt1[x];i++) if(pre[i]+suf[y]>0) {flag=1; break;}if(!(flag|=(!nxt1[x]))) {x=nxt1[x]; continue;} flag=0;for(int i=y+1;i<=nxt2[y];i++) if(pre[x]+suf[i]>0) {flag=1; break;}if(flag|=(!nxt2[y])) break; y=nxt2[y];}if(flag) {flag=0,puts("No"); continue;}for(int x=cnt1,y=cnt2;nxt1[x]||nxt2[y];flag=0){for(int i=x-1;i>=nxt1[x];i--) if(pre[i]+suf[y]>0) {flag=1; break;}if(!(flag|=(!nxt1[x]))) {x=nxt1[x]; continue;} flag=0;for(int i=y-1;i>=nxt2[y];i--) if(pre[x]+suf[i]>0) {flag=1; break;}if(flag|=(!nxt2[y])) break; y=nxt2[y];}puts(flag?"No":"Yes"),flag=0;}
    }
    

T2 排列

  • 部分分 \(50pts\):爆搜,发现 \(k=1\) 时为 \(2^{n-1}\)

  • 正解:

    逆天 DP,感觉不是我赛时能想出来的。

    \(f_{i,j,0/1,0/1}\) 表示长度为 \(i\) 的区间能在不超过 \(j\) 次操作后仅剩最大值的方案数,\(0/1\) 表示左/右端是否存在比区间最大值更大的值。

    转移考虑在两个区间的中间加入一个最大值 \(k\) 的贡献:

    • \(k\) 为整个序列最大值:

      \[f_{i,j,0,0}=\sum\limits_{k=1}^iC_{i-1}^{k-1}\times f_{k-1,j,0,1}\times f_{i-k,j,1,0} \]

    • \(k\) 为右区间最大值,左区间左侧还有更大值,左区间需要留一次操作消最大值 \(k\)

      \[f_{i,j,1,0}=\sum\limits_{k=1}^iC_{i-1}^{k-1}\times f_{k-1,j-1,1,1}\times f_{i-k,j,1,0} \]

    • \(k\) 位左区间最大值,右区间右侧还有更大值,同理:

      \[f_{i,j,0,1}=\sum\limits_{k=1}^iC_{i-1}^{k-1}\times f_{k-1,j,0,1}\times f_{i-k,j-1,1,1} \]

    • 左右区间两侧都有更大值,左右任意区间在 \(j-1\) 内消完即可,去掉两边都是 \(j\) 的贡献:

      \[f_{i,j,1,1}=\sum\limits_{k=1}^iC_{i-1}^{k-1}\times [f_{k-1,j,1,1}\times f_{i-k,j,1,1}-(f_{k-1,j,1,1}-f_{i-k,j-1,1,1})\times (f_{i-k,j,1,1}-f_{i-k,j-1,1,1})] \]

    最后答案为 \(f_{n,n,0,0}\),发现每次操作最少消除 \(\dfrac{n}{2}\) 个点,所以合法的 \(m\le \log_2(n)\),复杂度 \(O(n^2m)\) 实则为 \(O(n^2\log n)\) 级别,需特判不合法的 \(m\)

    点击查看代码
    #include<bits/stdc++.h>
    #define ll long long
    #define endl '\n'
    #define sort stable_sort
    using namespace std;
    const int N=1010;
    template<typename Tp> inline void read(Tp&x)
    {x=0;register bool z=true;register char c=getchar_unlocked();for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);x=(z?x:~x+1);
    }
    template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
    template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
    template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
    template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
    int n,m,P,c[N][N],f[N][11][2][2];
    inline int mod(int x,int y) {return (x+=y)>=P?x-P:x;}
    signed main()
    {read(n,m,P); if(m>10) return write(0),0;for(int i=0;i<=n;i++) c[i][0]=1;for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) c[i][j]=mod(c[i-1][j],c[i-1][j-1]);for(int i=0;i<=m;i++) f[0][i][0][0]=f[0][i][0][1]=f[0][i][1][0]=f[0][i][1][1]=1;for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) for(int k=1;k<=i;k++){f[i][j][0][0]=mod(f[i][j][0][0],1ll*f[k-1][j][0][1]*f[i-k][j][1][0]%P*c[i-1][k-1]%P);f[i][j][1][0]=mod(f[i][j][1][0],1ll*f[k-1][j-1][1][1]*f[i-k][j][1][0]%P*c[i-1][k-1]%P);f[i][j][0][1]=mod(f[i][j][0][1],1ll*f[k-1][j][0][1]*f[i-k][j-1][1][1]%P*c[i-1][k-1]%P);f[i][j][1][1]=mod(f[i][j][1][1],1ll*(1ll*f[k-1][j][1][1]*f[i-k][j][1][1]%P-1ll*(f[k-1][j][1][1]-f[k-1][j-1][1][1])*(f[i-k][j][1][1]-f[i-k][j-1][1][1])%P+P)%P*c[i-1][k-1]%P);}write(mod(f[n][m][0][0],P-f[n][m-1][0][0]));
    }
    

T3 最短路

  • 部分分 \(70pts\sim 99pts\):爆搜加剪枝。

  • 部分分 \(99pts\):丁真的假做法。

  • 部分分 \(99pts\):建反图,\(dis_{i,j}\) 表示从 \(1\) 沿正边跑到 \(i\) 加上沿反边跑到 \(j\) 的距离和,那么答案就是 \(dis_{n,n}\),bitset 压状态判有没有走过一个点,跑二维 dijkstra。最短路径不唯一的时候就死了,复杂度 \(O(m\log m)\)

  • 正解:

    考虑 \(n\to 1\) 的路径一定是沿着 \(1\to n\) 的路径走一段,再沿着不是 \(1\to n\) 的路径走一段,如此往复,称这一段的起点为 A 类点,终点为 B 类点,那么 A 和 B 一定交错出现,\(f_{i,j}\) 表示 \(i\) 为当前最后一个 A,\(j\) 为当前最后一个 B,\(g_{i,j}\) 类似的表示 \(i,j\) 均为 A,那么对于 \(f\) 枚举下一个 A,\(g\) 枚举中间的 A,发现又可以二维 dijkstra 了,复杂度 \(O(n^3\log n)\)

    点击查看代码
    #include<bits/stdc++.h>
    #define ll long long
    #define endl '\n'
    #define sort stable_sort
    using namespace std;
    const int N=255;
    template<typename Tp> inline void read(Tp&x)
    {x=0;register bool z=true;register char c=getchar_unlocked();for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);x=(z?x:~x+1);
    }
    template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
    template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
    template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
    template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
    int n,m,a[N],dis[N][N],f[2][N][N]; bool vis[2][N][N];
    struct aa
    {int op,x,y,w;inline bool operator < (const aa a) const {return w>a.w;}
    }; priority_queue<aa>q;
    signed main()
    {read(n,m),memset(f,0x3f,sizeof(f)),memset(dis,0x3f,sizeof(dis));for(int i=1;i<=n;i++) read(a[i]),dis[i][i]=a[i];for(int i=1,x,y;i<=m;i++) read(x,y),dis[x][y]=min(dis[x][y],a[x]+a[y]);for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) if(dis[i][k]!=0x3f3f3f3f)for(int j=1;j<=n;j++) if(dis[k][j]!=0x3f3f3f3f)dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]-a[k]);for(f[0][1][1]=a[1],q.push({0,1,1,a[1]});!q.empty();){aa it=q.top(); q.pop(); int op=it.op,x=it.x,y=it.y;if(vis[op][x][y]) continue; vis[op][x][y]=1;if(!op) for(int z=1,w;z<=n;z++){w=f[0][x][y]+dis[y][z]-a[y]-(x==z&&x!=y)*a[z];if(f[1][x][z]>w) f[1][x][z]=w,q.push({1,x,z,w});}else for(int z=1,w;z<=n;z++){w=f[1][x][y]+dis[y][z]+dis[z][x]-a[x]-a[y]-a[z]+(x==z&&x==y)*a[z];if(f[0][y][z]>w) f[0][y][z]=w,q.push({0,y,z,w});}}write(f[0][n][n]==0x3f3f3f3f?-1:f[0][n][n]);
    }
    

T4 矩形

写一个错误的解法吧,复杂度貌似能卡,随机数据下应该是 \(O(n\log n)\)

直接扫描线加并查集,扫到第一条边的时候查一下扔到并查集里,第二条边直接加进去即可。

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
#define mid (l+r>>1)
#define ls (mid<<1)
#define rs (mid<<1|1)
using namespace std;
const int N=1e5+10;
template<typename Tp> inline void read(Tp&x)
{x=0;register bool z=true;register char c=getchar_unlocked();for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);x=(z?x:~x+1);
}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
int n,m,ans,f[N],up[N<<1],val[N<<1],now[N<<1],add[N<<1];
struct aa {int x1,y1,x2,y2;}e[N];
inline int find(int x) {return x==f[x]?x:f[x]=find(f[x]);}
inline void pushup(int p,int l,int r)
{if(val[ls]==2||val[rs]==2) val[p]=2;else if(now[ls]==now[rs]) now[p]=now[ls],up[p]=up[ls],val[p]=1;else val[p]=2;
}
inline void spread(int p,int l,int r)
{add[ls]=add[rs]=add[p],now[ls]=now[rs]=now[p],up[ls]=up[rs]=up[p],add[p]=0;}
inline void change(int p,int l,int r,int vl,int vr,int d,int id)
{if(vl<=l&&vr>=r&&val[p]==1) return (up[p]<d)&&(up[p]=d)&&(now[p]=id)&&(add[p]=1),void();if(add[p]) spread(p,l,r);if(vl<=mid) change(ls,l,mid,vl,vr,d,id);if(vr>mid) change(rs,mid+1,r,vl,vr,d,id);pushup(p,l,r);
}
inline void ask(int p,int l,int r,int vl,int vr,int d,int id)
{if(vl<=l&&vr>=r&&val[p]==1)return (up[p]>=d)&&(f[find(id)]=find(now[p])),void();if(add[p]) spread(p,l,r);if(vl<=mid) ask(ls,l,mid,vl,vr,d,id);if(vr>mid) ask(rs,mid+1,r,vl,vr,d,id);
}
signed main()
{read(n); for(int i=1;i<=n;i++) f[i]=i;for(int i=1,a,b,c,d;i<=n;i++) read(a,b,c,d),e[i]={a,b,c,d},m=max({m,b,d});fill(val+1,val+1+(m<<1),1);sort(e+1,e+1+n,[](aa a,aa b){return a.x1==b.x1?a.x2<b.x2:a.x1<b.x1;});for(int i=1;i<=n;i++){ask(1,1,m,e[i].y1,e[i].y2,e[i].x1,i);change(1,1,m,e[i].y1,e[i].y2,e[i].x2,i);}for(int i=1;i<=n;i++) ans+=(f[i]==i); write(ans);
}

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

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

相关文章

AI辅助动画制作,现实到虚拟仅需要一个摄像头。多种AI技术融合赋能传统行业,或是产业趋势?

AI辅助动画制作,现实到虚拟仅需要一个摄像头。图源:youtube authour autodesk media & entertainment 不是元宇宙,是动画。 2024年10.30日。美国加利福尼亚公司 Wonder dynamic 发布了最新的产品视频。只需要一个摄像头,我们可以把所有的一切搬到虚拟世界。此产品利用多…

chapter14

第一题问题首先,编写一个名为 null.c 的简单程序,它创建一个指向整数的指针,将其设置为NULL,然后尝试对其进行释放内存操作。把它编译成一个名为 null 的可执行文件。当你运行这个程序时会发生什么?自己写的输出如下:无任何输出或错误提示。 第二题问题接下来,编译该程序…

0XGAME [Week 3] 重生之我在南邮当CTF大王

0XGAME [Week 3] 重生之我在南邮当CTF大王 新尝试:源文件找线索;新知识:兽音加密 下载是个游戏和源代码,玩了以下,感觉答对问题也是可以得到flag,但是感觉耗时,而且应该有藏flag的地方,在一堆文件里面找,data文件夹里面的4个地图json文件,进去发现了flag字眼是个2,那…

sentinel微服务限流

sentinel(微服务限流) 官网地址:https://sentinelguard.io/zh-cn/ 随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是由阿里巴巴开源的一款流量防护组件,Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。 微服…

RabbitMQ工作模式

RabbitMQ工作模式RabbitMQ提供了多种工作模式:简单模式,work模式 ,Publish/Subscribe发布与订阅模式,Routing路由模式,Topics主题模式等官网对应模式介绍:https://www.rabbitmq.com/getstarted.html 1、简单模式 生产者直接发送消息到队列上(虽然没有指明使用交换机,但是…

RabbitMQ消息幂等性保障

消息幂等性保障幂等性指一次和多次请求某一个资源,对于资源本身应该具有同样的结果。也就是说,其任意多次执行对资源本身所产生的影响均与一次执行的影响相同。在MQ中指,消费多条相同的消息,得到与消费该消息一次相同的结果消息幂等性保障 乐观锁机制 @Component public class …

WPF Button控件 这里可以点一下

WPF Button控件 这里可以点一下button表示一个 Windows 按钮控件,该控件对 Click 事件做出反应。 可以点一下button,执行程序操作,如:显示对话框,更改显示内容。 button的content属性表示按钮上显示的文字。<StackPanel><!-- 一个按钮控件,太小了,根本就看不到…

WPF Textbox控件 这里可以输入文字

WPF Textbox控件 这里可以输入文字 textbox控件,用于输入文字。如网页上输入账号密码的地方就是文本框。 文本框的text属性可以提示文字,只能包含无格式文本。

蛋白粉?蛋白质

蛋白粉不能用开水冲,但我们摄入的蛋白质却大都经过了烹煮。 为什么蛋白质不怕开水,而蛋白粉怕开水? 这似乎是矛盾的,其实不然。 问题是,很多人并不了解蛋白质的分子结构,不了解蛋白粉的溶解原理。 如果不了解其中的原理,很容易给出错误的解释。咳咳咳~~干货内容一次可…

【考试题解】多校A层冲刺NOIP2024模拟赛18

目录A. 选彩笔(rgb)题目内容部分分正解思路代码B. 兵蚁排序(sort)题目内容部分分75pts正解思路代码C. 人口局DBA(dba)题目内容部分分60pts正解思路代码D. 银行的源起(banking) A. 选彩笔(rgb) 题目内容 有 \(N\) 支彩笔,每支彩笔有 \(R_i,G_i,B_i\) 三个属性。定义两只彩笔 \(…

学习笔记(二十五):ArkUi-栅格布局 (GridRow/GridCol)

概述: 栅格布局是一种通用的辅助定位工具,对移动设备的界面设计有较好的借鉴作用。主要优势包括:提供可循的规律:栅格布局可以为布局提供规律性的结构,解决多尺寸多设备的动态布局问题。通过将页面划分为等宽的列数和行数,可以方便地对页面元素进行定位和排版。统一的定位…