【题解】牛客IOI周赛27-提高组

前言

在家闲着没事打牛客,发现自己被虐了。。。

好像别人的做法都很妙的样子。。。

A. 括号串

模拟题。

判断所给字符串合法等价于:

  1. 括号完全匹配
  2. A 串是 B 串的子序列

题意很扯淡。我最开始看到字符串长度可以比最小的小,可以删除 qwq

#include<bits/stdc++.h> #define PII pair<int,int> using namespace std; const int mx=1e6+5; int n,m,s[mx],cnt; char a[mx],b[mx]; bool match(char x,char y) { return x=='('&&y==')'||x=='['&&y==']'; } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d%s%s",&n,&m,a+1,b+1); cnt=0; for(int i=1;i<=m;i++) { if(b[i]=='['||b[i]=='(') { s[++cnt]=i; } else { if(cnt&&match(b[s[cnt]],b[i])) { cnt--; } else { cnt++; break; } } } if(cnt) { printf("Wrong Answer\n"); continue; } int j=1; for(int i=1;i<=m;i++) { if(j<=n&&a[j]==b[i]) j++; } if(j==n+1) { printf("Accepted\n"); } else { printf("Wrong Answer\n"); } } }

B. 虎龙斗

被虐了 qwq

首先想贪心做法,枚举 A 中选几个, B 中选 l-i 个,然后归并排序合并就完了 qwq 。然而这种贪心是错的,如下数据 :

3 3 6 1 1 1 1 1 2

显然先选下面的序列更优,然而我粗略地选了前一个就跑了导致只有 60pts。 这个时候贪心做不出来就自闭了,然后想 dp ,发现状态设计不出来。。。

后来看到一堆 O(n^2logn) 的线段树做法,自己也不会就只会 O(n^3) 的大众做法了:

仍然考虑上述贪心,有结论:选取字典序较大的那个一定更优(假若当前位相同)。

例子:

3 3 6 1 3 1 1 3 2

证明也很简单。考虑不同的那一位,假设 A<B,如果 AB 前面,那么调换两个字符串位置显然不会有影响,保证 BA 前面且答案更大,所以 A 只能在 B 后面,那么一定存在一个时刻两个串选了相同的前缀,而这是包含在先选 B 的决策中的。

#include<bits/stdc++.h> #define PII pair<int,int> #define INF 0x3f3f3f3f using namespace std; //思路:贪心 + dp //我太菜了 qwq... int n,m,l,A[505],B[505],E[505],F[505],G[1005],H[1005],s[505],cnt; vector<int> C[505],D[505]; bool chk(int *G,int *H) { for(int i=1;i<=l;i++) { if(G[i]!=H[i]) return G[i]>H[i]; if(G[i]==-INF&&H[i]==-INF) return 0; } return 0; } int main() { memset(B,-0x3f,sizeof(B)); memset(A,-0x3f,sizeof(A)); memset(H,-0x3f,sizeof(H)); scanf("%d%d%d",&n,&m,&l); for(int i=1;i<=n;i++) scanf("%d",&A[i]); for(int i=1;i<=m;i++) scanf("%d",&B[i]); for(int i=1;i<=n;i++) { int k=n-i; cnt=0; for(int j=1;j<=n;j++) { while(k&&cnt&&A[s[cnt]]<A[j]) { cnt--,k--; } s[++cnt]=j; } for(int j=1;j<=i;j++) { C[i].push_back(A[s[j]]); } } for(int i=1;i<=m;i++) { int k=m-i; cnt=0; for(int j=1;j<=m;j++) { while(k&&cnt&&B[s[cnt]]<B[j]) { cnt--,k--; } s[++cnt]=j; } for(int j=1;j<=i;j++) { D[i].push_back(B[s[j]]); } } for(int i=0;i<=l;i++) { if(i>n||l-i>m) continue; memset(E,-0x3f,sizeof(E)),memset(F,-0x3f,sizeof(F)); int j,k,r; for(j=1;j<=i;j++) E[j]=C[i][j-1]; for(k=1;k<=l-i;k++) F[k]=D[l-i][k-1]; j=k=r=1; while(j<=i&&k<=l-i) { if(E[j]>F[k]) G[r++]=E[j++]; else if(E[j]<F[k]) G[r++]=F[k++]; else if(chk(E+j,F+k)){ G[r++]=E[j++]; } else { G[r++]=F[k++]; } } while(j<=i) G[r++]=E[j++]; while(k<=l-i) G[r++]=F[k++]; if(chk(G,H)) memcpy(H,G,sizeof(G)); } for(int i=1;i<=l;i++) printf("%d ",H[i]); }

C. 马老师

良心出题人。。。

不妨把二进制每一位 i 拆开考虑,发现就是一个裸的背包问题。

发现可以用前缀和优化,时间复杂度 O(nlogn)

#include<bits/stdc++.h> #define PII pair<int,int> #define INF 0x3f3f3f3f #define ll long long using namespace std; const int mx=5e6+5; const int mod=1e9+7; //背包问题 //前缀和优化,时间复杂度 O(nlogn) int n,m; int dp[mx],sum[mx],res; int main() { scanf("%d%d",&n,&m); dp[0]=sum[0]=1; for(int i=0;i<25;i++) { for(int j=(1<<i);j<=m;j++) { sum[j]=(sum[j-(1<<i)]+dp[j])%mod; } for(int j=(1<<i);j<=m;j++) { if(j<1ll*(n+1)*(1<<i)) dp[j]=(dp[j]+sum[j-(1<<i)])%mod; else dp[j]=(dp[j]+sum[j]-sum[j-(n+1)*(1<<i)])%mod; if(dp[j]<0) dp[j]+=mod; } if((1<<i+1)>m) { break; } } printf("%d",dp[m]); }

D. 渡摆车

话说是增广路算法。。。

咕咕咕


__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530316.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(7)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示