多校A层冲刺NOIP2024模拟赛03

多校A层冲刺NOIP2024模拟赛03

\(T1\) A. 五彩斑斓(colorful) \(90/100pts\)

  • 部分分

    • \(20pts\) :枚举左上 \((k,h)\) 、右下端点 \((i,j)\) ,时间复杂度为 \(O(n^{2}m^{2})\)
    • \(90/100pts\)
      • \(a_{i,j} \ne a_{k,j}\) 时任意的 \(h \in [1,j]\) 都符合题意、

      • 不妨钦定 \(a_{i,j}=a_{k,j}\) ,则符合题意的 \(h \in [1,j]\) 必须满足 \(a_{k,h} \ne a_{i,j} \lor a_{i,h}=a_{i,j}\)

      • bitset 记录下 \((i,j)\) 前与 \(a_{i,j}\) 的相等情况。再将两者或一下求 \(1\) 的个数即可。

      • 时间复杂度为 \(O(\frac{n^{2}m \log m}{w})\)

        点击查看代码
        int a[410][410];
        bitset<410>vis[410][410],tmp;
        int main()
        {freopen("colorful.in","r",stdin);freopen("colorful.out","w",stdout);int n,m,i,j,k;ll ans=0;scanf("%d%d",&n,&m);for(i=1;i<=n;i++){for(j=1;j<=m;j++){scanf("%d",&a[i][j]);for(k=1;k<=j;k++){vis[i][j][k]=(a[i][k]!=a[i][j]);}for(k=1;k<=i;k++){if(a[i][j]!=a[k][j]){ans+=j;}else{tmp=vis[k][j]|vis[i][j];ans+=tmp.count();}}}}printf("%lld\n",ans);fclose(stdin);fclose(stdout);return 0;
        }
        
  • 正解

    • 正难则反,考虑统计四个角都相等的子矩阵数列,再用总子矩阵 \(\frac{nm(n+1)(m+1)}{4}\) 减去。
    • 仍考虑枚举 \(a_{i,j}\)\(a_{k,j}\) 作为右上和右下端点,钦定 \(a_{i,j}=a_{k,j}\) ,开个桶计算 \(h \in [1,j]\) 中满足 \(a_{k,h}=a_{i,h}=a_{k,j}=a_{i,j}\) 的个数即可。
    • 时间复杂度为 \(O(n^{2}m)\)
    点击查看代码
    ll a[410][410],cnt[1000010];
    int main()
    {freopen("colorful.in","r",stdin);freopen("colorful.out","w",stdout);ll n,m,ans,i,j,k;cin>>n>>m;ans=n*(n+1)*m*(m+1)/4;for(i=1;i<=n;i++){for(j=1;j<=m;j++){cin>>a[i][j];}}for(i=1;i<=n;i++){for(k=1;k<=i;k++)	{for(j=1;j<=m;j++)	{if(a[i][j]==a[k][j]){cnt[a[i][j]]++;ans-=cnt[a[i][j]];}}for(j=1;j<=m;j++)	{if(a[i][j]==a[k][j]){cnt[a[i][j]]--;}}}}cout<<ans<<endl;fclose(stdin);fclose(stdout);return 0;
    }
    

\(T2\) B. 错峰旅行(travel) \(70pts\)

  • 对时间偏移是显然的。

  • \(V=t-s\)

  • 部分分

    • \(45 \%\)
      • \(f_{i,j}\) 表示第 \(i\) 天在城市 \(j\) 的方案数,状态转移方程为 \(f_{i,j}=check(i,j) \times \sum\limits_{k=1}^{f_{i-1,k}}\) ,其中 \(check(i,j)=\begin{cases} 1 & 城市 j 在第 i 天不拥挤 \\ 0 & 城市 j 在第 i 天拥挤 \end{cases}\) ,边界为 \(f_{0,i}=check(0,i)\)

      • 判断某个城市在转移过程中是否拥挤用单调数据结构维护一下即可。

      • 观察到 \(f\) 的转移过程可以前缀和优化,时间复杂度为 \(O(nV)\) ,可以获得 \(50pts\)

        点击查看代码
        const ll p=1000000007;
        ll f[2][5010];
        vector<pair<ll,ll> >e[5010];
        bool cmp(pair<ll,ll> a,pair<ll,ll> b)
        {return a.first>b.first;
        }
        int main()
        {freopen("travel.in","r",stdin);freopen("travel.out","w",stdout);ll n,m,s,t,x,l,r,ans=0,sum,i,j,k;cin>>n>>m>>s>>t;t-=s;for(i=1;i<=m;i++){cin>>x>>l>>r;l-=s;r-=s;e[x].push_back(make_pair(l,r));}for(i=1;i<=n;i++){sort(e[i].begin(),e[i].end(),cmp);f[0][i]=(!(e[i].empty()==0&&e[i].back().first<=0&&0<=e[i].back().second));}for(i=1;i<=t;i++){sum=0;for(j=1;j<=n;j++){sum=(sum+f[(i-1)&1][j])%p;}for(j=1;j<=n;j++){f[i&1][j]=0;while(e[j].empty()==0&&e[j].back().second<i){e[j].pop_back();}f[i&1][j]=sum*(!(e[j].empty()==0&&e[j].back().first<=i&&i<=e[j].back().second));}}for(i=1;i<=n;i++){ans=(ans+f[t&1][i])%p;}cout<<ans<<endl;fclose(stdin);fclose(stdout);return 0;
        }
        
      • 又有 \(\sum\limits_{j=1}^{n}f_{i,j}=\sum\limits_{j=1}^{n}f_{i-1,j} \times \sum\limits_{j=1}^{n}check(i,j)\) ,所以可以只记录第 \(i\) 天不拥挤的城市个数来进行转移。时间复杂度仍为 \(O(nV)\) ,但常数有所减小,可以获得 \(60pts\)

        点击查看代码
        const ll p=1000000007;
        vector<pair<ll,ll> >e[5010];
        bool cmp(pair<ll,ll> a,pair<ll,ll> b)
        {return a.first>b.first;
        }
        int main()
        {freopen("travel.in","r",stdin);freopen("travel.out","w",stdout);ll n,m,s,t,x,l,r,ans=0,cnt=0,i,j,k;cin>>n>>m>>s>>t;t-=s;for(i=1;i<=m;i++){cin>>x>>l>>r;l-=s;r-=s;e[x].push_back(make_pair(l,r));}for(i=1;i<=n;i++){sort(e[i].begin(),e[i].end(),cmp);ans+=(!(e[i].empty()==0&&e[i].back().first<=0&&0<=e[i].back().second));}for(i=1;i<=t;i++){cnt=0;for(j=1;j<=n;j++){while(e[j].empty()==0&&e[j].back().second<i){e[j].pop_back();}cnt+=(!(e[j].empty()==0&&e[j].back().first<=i&&i<=e[j].back().second));}ans=cnt*ans%p;}cout<<ans<<endl;fclose(stdin);fclose(stdout);return 0;
        }
        
      • 现在问题来到了怎么快速求出某一天不拥挤的城市个数。而某一天拥挤的城市个数可以通过线段树区间加、单点查询实现,空间复杂度为 \(O(m \log V)\) ,时间复杂度为 \(O((m+V) \log V)\) ,可以获得 \(70pts\)

        点击查看代码
        const ll p=1000000007;
        struct SMT
        {int root=0,rt_sum=0;struct SegmentTree{int ls,rs,lazy;}tree[10000010];#define lson(rt) (tree[rt].ls)#define rson(rt) (tree[rt].rs)int build_rt(){rt_sum++;lson(rt_sum)=rson(rt_sum)=tree[rt_sum].lazy=0;return rt_sum;}void update(int &rt,int l,int r,int x,int y,int val){rt=(rt==0)?build_rt():rt;if(x<=l&&r<=y){tree[rt].lazy+=val;return;}int mid=(l+r)/2;if(x<=mid){update(lson(rt),l,mid,x,y,val);}if(y>mid){update(rson(rt),mid+1,r,x,y,val);}}int query(int rt,int l,int r,int pos){if(rt==0){return 0;}if(l==r){return tree[rt].lazy;}int mid=(l+r)/2;if(pos<=mid){return query(lson(rt),l,mid,pos)+tree[rt].lazy;}else{return query(rson(rt),mid+1,r,pos)+tree[rt].lazy;}}
        }T;
        int main()
        {freopen("travel.in","r",stdin);freopen("travel.out","w",stdout);int n,m,s,t,x,l,r,i;ll ans=1;scanf("%d%d%d%d",&n,&m,&s,&t);t-=s;T.update(T.root,0,t,0,t,n);for(i=1;i<=m;i++){scanf("%d%d%d",&x,&l,&r);l-=s;r-=s;T.update(T.root,0,t,l,r,-1);}for(i=0;i<=t;i++){ans=ans*T.query(T.root,0,t,i)%p;}printf("%lld\n",ans);fclose(stdin);fclose(stdout);return 0;
        }
        
      • 线段树难以维护区间乘积,考虑低配版珂朵莉树(没有推平操作)维护上述过程,可以获得 \(80pts\)

        点击查看代码
        const ll p=1000000007;
        ll qpow(ll a,ll b,ll p)
        {ll ans=1;while(b){if(b&1){ans=ans*a%p;}b>>=1;a=a*a%p;}return ans;
        }
        struct ODT
        {struct node{ll l,r;mutable ll col;bool operator < (const node &another) const{return l<another.l;}};set<node>s;void init(ll n,ll t){s.insert((node){0,t,n});}set<node>::iterator split(ll pos){set<node>::iterator it=s.lower_bound((node){pos,0,0});if(it!=s.end()&&it->l==pos){return it;}it--;if(it->r<pos){return s.end();}ll l=it->l,r=it->r,col=it->col;s.erase(it);s.insert((node){l,pos-1,col});return s.insert((node){pos,r,col}).first;}void update(ll l,ll r,ll val){set<node>::iterator itr=split(r+1),itl=split(l);for(set<node>::iterator it=itl;it!=itr;it++){it->col+=val;}}ll query(ll l,ll r){set<node>::iterator itr=split(r+1),itl=split(l);ll ans=1;for(set<node>::iterator it=itl;it!=itr;it++){ans=ans*qpow(it->col,it->r-it->l+1,p)%p;}return ans;}
        }D;
        int main()
        {freopen("travel.in","r",stdin);freopen("travel.out","w",stdout);ll n,m,s,t,x,l,r,i;scanf("%lld%lld%lld%lld",&n,&m,&s,&t);t-=s;D.init(n,t);for(i=1;i<=m;i++){scanf("%lld%lld%lld",&x,&l,&r);l-=s;r-=s;D.update(l,r,-1);}printf("%lld\n",D.query(0,t));fclose(stdin);fclose(stdout);return 0;
        }
        
  • 正解

    • 先对所有时间进行离散化。
    • 类似珂朵莉树考虑维护一段时间内不拥挤城市不变的时间段对答案的影响。
    • 具体地,因为是静态修改所以考虑差分,接着双指针维护不拥挤城市即可。
    点击查看代码
    const ll p=1000000007;
    ll a[2000010],d[2000010];
    struct node
    {ll x,tim,val;
    }e[2000010];
    bool cmp(node a,node b)
    {return (a.tim==b.tim)?(a.val<b.val):(a.tim<b.tim);
    }
    ll qpow(ll a,ll b,ll p)
    {ll ans=1;while(b){if(b&1){ans=ans*a%p;}b>>=1;a=a*a%p;}return ans;
    }
    int main()
    {freopen("travel.in","r",stdin);freopen("travel.out","w",stdout);ll n,m,s,t,x,l,r,ans=1,num,i;scanf("%lld%lld%lld%lld",&n,&m,&s,&t);num=n;a[1]=s;a[2]=t+1;for(i=1;i<=m;i++){scanf("%lld%lld%lld",&x,&l,&r);e[2*i-1]=(node){x,l,1};e[2*i]=(node){x,r+1,-1};a[2*i+1]=l;a[2*i+2]=r+1;}sort(e+1,e+1+2*m,cmp);sort(a+1,a+1+2+2*m);a[0]=unique(a+1,a+1+2+2*m)-(a+1);for(l=r=1;r<=a[0]-1;r++){for(;l<=2*m&&e[l].tim<=a[r];l++){if(e[l].val==1){num-=(d[e[l].x]==0);}if(e[l].val==-1){num+=(d[e[l].x]==1);}d[e[l].x]+=e[l].val;}ans=ans*qpow(num,a[r+1]-a[r],p)%p;}	printf("%lld\n",ans);fclose(stdin);fclose(stdout);return 0;
    }
    

\(T3\) C. 线段树(segment) \(100pts\)

  • 详见 NOIP2024模拟2 T3 GHzoj 3733. 线段树 。

\(T4\) D. 量子隧穿问题(experiment) \(14/5pts\)

  • 部分分

    • \(14/5pts\) :爆搜。

      点击查看代码
      const ll p=1000000007;
      int b[5010],vis[5010],tmp[5010],ans=0;
      char s[5010];
      void dfs(int pos,int n)
      {if(pos==n+1){for(int i=1;i<=n;i++){tmp[i]=vis[i];}for(int i=1;i<=n;i++){if(tmp[i]==1){if(tmp[b[i]]==0){tmp[i]=0;tmp[b[i]]=1;}}}ans=(ans+tmp[n])%p;return;}else{if(s[pos]=='C'){vis[pos]=1;dfs(pos+1,n);}if(s[pos]=='.'){vis[pos]=0;dfs(pos+1,n);}if(s[pos]=='?'){vis[pos]=1;dfs(pos+1,n);vis[pos]=0;dfs(pos+1,n);}}
      }	
      int main()
      {freopen("experiment.in","r",stdin);freopen("experiment.out","w",stdout);int t,n,i,j;scanf("%d",&t);for(j=1;j<=t;j++){ans=0;scanf("%d%s",&n,s+1);for(i=1;i<=n;i++){scanf("%d",&b[i]);}dfs(1,n);printf("%d\n",ans);}fclose(stdin);fclose(stdout);return 0;
      }
      
  • 正解

    • 考虑将计数 \(DP\) 转化为概率 \(DP\) ,最后再乘上 \(2^{k}\)
    • \(i\)\(b_{i}\) 连一条有向边,于是就得到了一个基环树森林。每棵基环树彼此间是互不相关的,故可以只考虑包含盒子 \(n\) 的基环树。
    • \(f_{i,j}\) 表示狗当前跑到盒子 \(i\) 时盒子 \(j\) 有猫的概率。
    • 先考虑如果是棵树怎么处理。对于树上一条边 \(u \to v\) ,有 \(\begin{cases} f_{u,u}=f_{u-1,u} \times f_{u-1,v} \\ f_{u,v}=f_{u-1,v}+f_{u-1,u} \times (1-f_{u-1,v}) \end{cases}\) ,边界为 \(f_{0,i}=[s_{i}=C]+[s_{i}=?] \times \frac{1}{2}\)
    • 而到基环树上状态的转移之间具有后效性,因为 \(n\) 过大所以无法高斯消元。
    • 对于基环树的环上第一条边(起点编号最小的边) \(u \to v\) ,不妨钦定 \(u,v\) 有/无猫,然后就能当成树来做了。
      • 之所以取第一条边是为了保证 \(u\) 已经更新完与之相连的环外的节点。
      • 因为直接按照树来做的话,当 \(u\) 更新 \(v\) 时没有计算 \(u\) 在环上的父亲对 \(u\) 的贡献,所以需要钦定后再按照树来做。
    点击查看代码
    const ll p=1000000007;
    struct node
    {ll nxt,to;
    }e[10010];
    ll head[10010],to[10010],vis[10010],f[10010],cnt=0;
    char s[10010];
    void add(ll u,ll v)
    {cnt++;e[cnt].nxt=head[u];e[cnt].to=v;head[u]=cnt;
    }
    ll qpow(ll a,ll b,ll p)
    {ll ans=1;while(b){if(b&1){ans=ans*a%p;}b>>=1;a=a*a%p;}return ans;
    }
    struct DSU
    {ll fa[100010];void init(ll n){for(ll i=1;i<=n;i++){fa[i]=i;}}ll find(ll x){return (fa[x]==x)?x:fa[x]=find(fa[x]);}void merge(ll x,ll y){x=find(x);y=find(y);if(x!=y){fa[x]=y;}}
    }D;
    ll dfs_huan(ll x)
    {vis[x]=1;return (vis[to[x]]==1)?x:dfs_huan(to[x]);
    }
    void dfs(ll x,ll &rt)
    {rt=min(rt,x);vis[x]=1;if(vis[to[x]]==0){dfs(to[x],rt);}
    }
    int main()
    {freopen("experiment.in","r",stdin);freopen("experiment.out","w",stdout);ll t,n,ans,sum,num,inv=qpow(2,p-2,p),rt,tmp,i,j,k,h;cin>>t;for(h=1;h<=t;h++){cnt=ans=sum=0;memset(e,0,sizeof(e));memset(head,0,sizeof(head));memset(vis,0,sizeof(vis));cin>>n>>(s+1);D.init(n);for(i=1;i<=n;i++){cin>>to[i];add(i,to[i]);D.merge(i,to[i]);sum+=(s[i]=='?');}for(i=1;i<=n;i++){if(D.find(i)==D.fa[n]){rt=dfs_huan(i);break;}}memset(vis,0,sizeof(vis));dfs(rt,rt);for(j=0;j<=1;j++){for(k=0;k<=1;k++){for(i=1;i<=n;i++){if(s[i]=='C'){f[i]=1;}if(s[i]=='.'){f[i]=0;}if(s[i]=='?'){f[i]=inv;}}for(i=1;i<=n;i++){if(i==rt){num=(j==1?f[i]:(1-f[i]+p)%p)*(k==1?f[to[i]]:(1-f[to[i]]+p)%p)%p;f[i]=j;f[to[i]]=k;}tmp=f[i];f[i]=f[i]*f[to[i]]%p;f[to[i]]=(f[to[i]]+((1-f[to[i]]+p)%p)*tmp%p)%p;}ans=(ans+num*f[n]%p)%p;}}cout<<ans*qpow(2,sum,p)%p<<endl;}fclose(stdin);fclose(stdout);return 0;
    }
    

总结

  • \(T2\) 没想到离散化去优化线段树的空间,而且对于静态区间修改没有马上想到差分可以处理,和 普及模拟3 T2 红黑树 犯了一样的问题。

后记

  • \(T3\) 被出在了以前和 \(GXYZ\) 一起打的模拟赛里, \(miaomiao\) 说不用管,正常做就行。

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

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

相关文章

Word中 Endnote 引用标蓝色

1. 打开word中的endnote加载项。如图所示,勾选这两个设置。 确认后会自动变为超链接,显示蓝色以及下划线。 2. 在样式设置中,将超链接的下划线取消。之后就会只显示蓝色引用。 结果显示:

中国大学生程序设计竞赛(秦皇岛)正式赛东北大学秦皇岛分校(SMU Autumn 2024 Team Round 1)

中国大学生程序设计竞赛(秦皇岛)正式赛东北大学秦皇岛分校(SMU Autumn 2024 Team Round 1) Problem A. 贵校是构造王国吗 I 思路 官方题解很清晰明了。代码 #include <bits/stdc++.h> using namespace std; #define int long long #define endl \n #define PII pair&…

多校 A 层冲刺 NOIP2024 模拟赛 03

多校 A 层冲刺 NOIP2024 模拟赛 03 T1 五彩斑斓(colorful) 签到题 直接暴力枚举是 \(O(n^4)\) ,考虑使用 \(bitset\) 优化,对每个点开个 \(bitset\),预处理它所在一行它及它之前相同颜色的位置,这样就只用枚举另一个点所在列,时间复杂度为 \(O(n^3+\frac{n^4}{w})\)。 T…

在浏览器上访问媒体资源配置【文件上传】

1.根urls.py文件中 from django.contrib import admin from django.urls import path, include, re_path from django.views.static import serve from django.conf import settingsurlpatterns = [# path(admin/, admin.site.urls),path(api/shipper/, include(apps.shipper.u…

高级程序语言设计第二次作业

姓名:袁志华 班级:软件工程2班 学号:102400231 班级网址:https://edu.cnblogs.com/campus/fzu/2024C 作业网址:https://edu.cnblogs.com/campus/fzu/2024C/homework/13282 图片: 第一题: 第二题: 第三题: 第四题: 第五题: 第六题: 第七题: 第八题:程序清单: 3.1…

macOS Sequoia 15.0.1 (24A348) 正式版 ISO、IPSW、PKG 下载

macOS Sequoia 15.0.1 (24A348) 正式版 ISO、IPSW、PKG 下载macOS Sequoia 15.0.1 (24A348) 正式版 ISO、IPSW、PKG 下载 iPhone 镜像、Safari 浏览器重大更新和 Apple Intelligence 等众多全新功能令 Mac 使用体验再升级 请访问原文链接:https://sysin.org/blog/macOS-Sequoi…

人群聚集监测预警系统

人群聚集监测预警系统采用AI视频智能分析技术,人群聚集监测预警系统通过在工地、工厂等场所已经安装监控摄像头,人群聚集监测预警系统对人员聚集情况进行实时监测,当人群聚集过于密集时,系统将自动发出警报,人群聚集监测预警系统并通过人工智能算法对人员的状态进行识别和…

智能烟火识别预警软件

智能烟火识别预警软件采用人工智能技术,智能烟火识别预警软件在工厂、工地等场所利用已经安装的摄像头,智能烟火识别预警软件对场内的烟花爆竹进行实时监测。当场内出现烟花爆竹时,智能烟火识别预警软件将自动发出警报,并通过人工智能算法通知现场管理人员进行处理。智能烟…

脱岗监测预警系统

脱岗监测预警系统可以通过对工人的位置进行实时监测,脱岗监测预警系统识别是否存在脱岗行为,并及时发出警报。脱岗监测预警系统在工作过程中,如果工人离开其工作位置,脱岗监测预警系统会自动识别并发出警报,提醒管理人员采取措施防止事故的发生。脱岗监测预警系统可以通过…

非煤矿山电子封条系统部署方案

非煤矿山电子封条系统部署方案是基于Ai视频图像识别技术,非煤矿山电子封条系统部署方案通过人工智能算法在矿山设备上安装电子封条,监控矿山矿井出入井人员、人员变化及非煤矿山生产作业状态等状况,及时发现处理非煤矿山异常动态将自动发出警报,及时通知现场管理人员进行处…

加油站员工行为监测预警系统

加油站员工行为监测预警系统可以通过对加油站员工进行实时监控,加油站员工行为监测预警系统识别是否存在不规范行为,并及时发出警报。在卸油作业过程中,加油站员工行为监测预警系统监测员工灭火器的正确放置、静电释放操作规范等作业状态,及时发出警报,提醒工作人员采取措…

矿山电子封条系统

矿山电子封条系统通过在煤矿关键地点安装摄像机以及边缘智能分析终端,矿山电子封条系统实时监测分析煤矿生产作业状态和矿井出入井人员、人数变化等情况,矿山电子封条系统利用智能化视频识别等技术及时发现煤矿异常动态,全天候不间断自动推送报警信息。相比传统的安全监管手…