2024.11.21 2024辽宁省赛
Solved:11/13
Penalty:1224
Rank:3
Rank(vp):5
没打过某两强校啊。。。
B. 比分幻术
签到,把输入的字符串反转输出。
#include<bits/stdc++.h> using namespace std; int main(){ ios::sync_with_stdio(0);cin.tie(0); string s; cin>>s; cout<<s[2]<<s[1]<<s[0]<<'\n'; }
J. 结课风云
签到,依次统计改分前后的通过人数。
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<ll,ll> pll; const int N=1005; int n,a,b,c,d,x[N],y[N]; int main(){ ios::sync_with_stdio(0);cin.tie(0); cin>>n>>a>>b>>c; int cnt1=0,cnt2=0; for(int i=1;i<=n;++i)cin>>x[i]>>y[i],cnt1+=x[i]+y[i]>=c; cin>>d; for(int i=1;i<=n;++i)x[i]=min(x[i]+d,a),cnt2+=x[i]+y[i]>=c; cout<<cnt2-cnt1<<'\n'; }
A. 爱上字典
不需要写哈希,直接用 set<string>
实现字符串查找,不会超时。
#include<bits/stdc++.h> using namespace std; int n; string s,t; set<string> ss; int main(){ ios::sync_with_stdio(0);cin.tie(0); getline(cin,s),s+=' '; cin>>n; for(int i=0;i<n;++i){ cin>>t; ss.insert(t); } n=ss.size(); int m=s.length(); ll h1=0,h2=0; t=""; for(int i=0;i<m;++i){ char ch=s[i]; if(ch>='A'&&ch<='Z')ch+=32; if(ch==' '){ if(ss.find(t)==ss.end())ss.insert(t); t=""; } if(ch>='a'&&ch<='z')t+=ch; } ss.erase(""); cout<<ss.size()-n<<'\n'; }
L. 龙之研习
题意:闰年规则改为
二分答案,问题转化为算
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<ll,ll> pll; ll q,m; ll chk(ll n){ ll ans=0; for(ll r=1;r<=n;r*=100){ ans+=n/r; ans-=n/(4*r); } return ans; } void solve(){ cin>>m; ll l=m+2024,r=2*m+2024,mid,res; while(l<=r){ mid=(l+r)>>1; if(chk(mid)-q>=m)res=mid,r=mid-1; else l=mid+1; } cout<<res<<'\n'; } int main(){ q=chk(2024); ios::sync_with_stdio(0);cin.tie(0); int T; cin>>T; while(T--)solve(); }
C. 插排串联
题意:给一棵树,可以任意交换非根非叶子节点,问能否使得对每个非叶子节点,其子树中所有叶子节点权值之和小于等于自身权值。
题意等价于给每个非根非叶子节点分配一个大于等于某限制的权值。multiset存待取权值,然后贪心选取最小的满足限制的权值即可。
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<ll,ll> pll; const int N=1e5+5; int n,x; ll a[N]; vector<int> e[N]; bool fl=1; void adde(int x,int y){ e[x].push_back(y); } multiset<ll> s; void dfs(int u){ if(!e[u].size())return; int sum=0; for(int v:e[u])dfs(v),sum+=a[v]; if(!u)return; auto it=s.lower_bound(sum); if(it==s.end()){fl=0;return;} a[u]=sum; s.erase(it); } int main(){ ios::sync_with_stdio(0);cin.tie(0); cin>>n; for(int i=1;i<=n;++i){ cin>>x>>a[i]; adde(x,i); } ll sum=0; for(int i=1;i<=n;++i){ if(e[i].size())s.insert(a[i]); else sum+=a[i]; } if(sum>2200){cout<<"NO\n";return 0;} dfs(0); cout<<(fl?"YES":"NO")<<'\n'; }
E. 俄式简餐
题意:用 L 形和 I 形俄罗斯方块填充
格子数不能被
-
或 :用 I 形填满即可; -
均不能被 整除:容易构造出 (或者 )的解,因此对前 行反复用 填,剩下用 I 填满即可。注意特判 (此时没有前 行)。
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<ll,ll> pll; const int N=1e5+5; int n,m; void solve(){ cin>>n>>m; if(n*m&3){cout<<"NO\n";return;} if(n==2&&m==2){cout<<"NO\n";return;} cout<<"YES\n"; if(!(n&3)){ for(int i=0;i<n;++i,cout<<'\n') for(int j=0;j<m;++j) cout<<(i>>2)*m+j+1<<' '; } else if(!(m&3)){ for(int i=0;i<n;++i,cout<<'\n') for(int j=0;j<m;++j) cout<<i*(m>>2)+(j>>2)+1<<' '; } else{ vector<vector<int>> a(n); for(int i=0;i<n;++i)a[i].resize(m); if(n==2){ a[0][0]=a[0][1]=a[0][2]=a[1][0]=1; a[0][3]=a[0][4]=a[0][5]=a[1][5]=2; a[1][1]=a[1][2]=a[1][3]=a[1][4]=3; int cnt=3; for(int i=6;i<m;i+=4){ a[0][i]=a[0][i+1]=a[0][i+2]=a[0][i+3]=++cnt; a[1][i]=a[1][i+1]=a[1][i+2]=a[1][i+3]=++cnt; } } else{ int cnt=0; for(int i=0;i<m;i+=2){ a[0][i]=a[1][i]=a[2][i]=a[0][i+1]=++cnt; a[3][i]=a[4][i]=a[5][i]=a[5][i+1]=++cnt; a[1][i+1]=a[2][i+1]=a[3][i+1]=a[4][i+1]=++cnt; } for(int i=6;i<n;i+=4) for(int j=0;j<m;++j) a[i][j]=a[i+1][j]=a[i+2][j]=a[i+3][j]=++cnt; } for(int i=0;i<n;++i,cout<<'\n') for(int j=0;j<m;++j) cout<<a[i][j]<<' '; } } int main(){ ios::sync_with_stdio(0);cin.tie(0); int T; cin>>T; while(T--)solve(); }
G. 顾影自怜
题意:给一个序列,问有多少连续子列的最大值出现次数
预处理每个值的所有出现位置(可以用vector数组)
首先枚举最大值
二分子列左端点的最左位置
总复杂度
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e6+5; int n,k,a[N],st[20][N]; vector<int> pos[N]; int qry(int l,int r){ int o=__lg(r-l+1); return max(st[o][l],st[o][r-(1<<o)+1]); } void solve(){ cin>>n>>k; for(int i=1;i<=n;++i)cin>>a[i],pos[a[i]].push_back(i),st[0][i]=a[i]; for(int i=1;1<<i<=n;++i) for(int j=1;j+(1<<i)-1<=n;++j) st[i][j]=max(st[i-1][j],st[i-1][j+(1<<i-1)]); ll ans=0; for(int i=1;i<=n;++i){ for(int j=0;j+k-1<pos[i].size();++j){ int lp=pos[i][j],rp=pos[i][j+k-1]; if(qry(lp,rp)>i)continue; int l=j?pos[i][j-1]+1:1,r=lp,mid,L=lp,R=rp; while(l<=r){ mid=(l+r)>>1; if(qry(mid,lp)==i)r=mid-1,L=mid; else l=mid+1; } l=rp,r=n; while(l<=r){ mid=(l+r)>>1; if(qry(rp,mid)==i)l=mid+1,R=mid; else r=mid-1; } ans+=1ll*(lp-L+1)*(R-rp+1); } } cout<<ans<<'\n'; for(int i=1;i<=n;++i)pos[i].clear(); } int main(){ ios::sync_with_stdio(0);cin.tie(0); int T; cin>>T; while(T--)solve(); }
D. 都市叠高
题意:给一列二维平面上的点,将它们划分为若干区间,使得每个区间的点形成的凸包直径之和最大。
这是一道套着计算几何的皮的简单dp题(
点集凸包的直径一定是最远点对的距离。而在最优划分方案中,我们一定会把最远的两个点分到区间的左右端点(否则将这个区间拆成两段或者三段一定更优)。
因此有转移
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=5005; int n,x[N],y[N]; double f[N]; double dis(int i,int j){ return sqrt(1.*(x[i]-x[j])*(x[i]-x[j])+1.*(y[i]-y[j])*(y[i]-y[j])); } int main(){ ios::sync_with_stdio(0);cin.tie(0); cin>>n; for(int i=1;i<=n;++i)cin>>x[i]>>y[i]; for(int i=1;i<=n;++i){ f[i]=f[i-1]; for(int j=1;j<i;++j) f[i]=max(f[i],f[j-1]+dis(i,j)); } cout<<fixed<<setprecision(12)<<f[n]<<'\n'; }
K. 可重集合
题意:维护一个可重集
如果没有删除操作,直接用 bitset 维护即可做到
直接删除是不能用 bitset 做的(这等价于从 01 背包里删一个物品)。
每个物品的存在时间是一个区间,因此可用线段树分治将“删除一个物品”转化为“撤销加入一个物品”(后者直接把原来的 bitset 状态存下来即可)。
复杂度
注:这个套路同样适用于一般的动态 01 背包问题。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=5005,M=5e5+5; int n,m=5e5,op[N],x[N]; vector<int> tr[N*4],s[M]; bitset<M> now; #define lc (x<<1) #define rc (x<<1|1) void insert(int x,int l,int r,int L,int R,int val){ if(l==L&&r==R){ tr[x].push_back(val); return; } int mid=(l+r)>>1; if(R<=mid)insert(lc,l,mid,L,R,val); else if(L>mid)insert(rc,mid+1,r,L,R,val); else insert(lc,l,mid,L,mid,val),insert(rc,mid+1,r,mid+1,R,val); } int ans[N]; void calc(int x,int l,int r){ bitset<M> tmp=now; for(int val:tr[x])now|=now<<val; if(l==r){ans[l]=now.count()-1,now=tmp;return;} int mid=(l+r)>>1; calc(lc,l,mid),calc(rc,mid+1,r); now=tmp; } int main(){ ios::sync_with_stdio(0);cin.tie(0); cin>>n; for(int i=1;i<=n;++i)cin>>op[i]>>x[i]; for(int i=1;i<=n;++i){ if(op[i]==1)s[x[i]].push_back(i); else insert(1,1,n,s[x[i]].back(),i-1,x[i]),s[x[i]].pop_back(); } for(int i=1;i<=m;++i) for(int j:s[i])insert(1,1,n,j,n,i); now[0]=1,calc(1,1,n); for(int i=1;i<=n;++i)cout<<ans[i]<<'\n'; }
M. 盲盒谜题
题意:大模拟,略。
直接按题意暴力做就好了。复杂度
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pii; const int N=1e5+5; int n,m,k,t,a[N],ans[N]; vector<array<int,3>> lines={ {1,2,9},{1,3,8},{1,4,7},{1,5,6}, {2,3,4},{2,5,7},{4,6,9},{7,8,9} }; int b[10]; bool empty(){ for(int i=1;i<=9;++i)if(~b[i])return 0; return 1; } int first_empty(){ for(int i=1;i<=9;++i)if(!~b[i])return i; return -1; } pii first_same(){ for(int i=1;i<=9;++i)if(~b[i]) for(int j=i+1;j<=9;++j)if(~b[j]) if(b[i]==b[j])return {i,j}; return {-1,-1}; } int main(){ ios::sync_with_stdio(0);cin.tie(0); cin>>n>>m>>k>>t; for(int i=1;i<=k;++i)cin>>a[i]; memset(b,-1,sizeof(b)); int l=1,cnt=n; bool end=0; while(!end){ end=1; bool sp=0; for(int i=1;i<=9;++i)if(!~b[i]){ if(l>min(k,cnt))break; end=0; if(a[l]==0){ ++l,++cnt,sp=1; break; } else{ b[i]=a[l]; if(a[l]==t)++cnt; ++l; } } if(sp)continue; if(!~first_empty()&&first_same()==pii(-1,-1)){ end=0,b[1]=-1; } sp=0; for(int i=0;i<8;++i)if(~b[lines[i][0]]&&b[lines[i][0]]==b[lines[i][1]]&&b[lines[i][1]]==b[lines[i][2]]){ end=0; if(lines[i][0]>1)b[lines[i][0]]=-1; else sp=1; b[lines[i][1]]=b[lines[i][2]]=-1; cnt+=5; } pii t; while((t=first_same())!=pii(-1,-1)){ end=0; if(t.first>1)b[t.first]=-1; else sp=1; b[t.second]=-1; ++cnt; } if(sp)b[1]=-1; if(end)break; if(empty())cnt+=10; } for(int i=1;i<=min(cnt,k);++i)++ans[a[i]]; for(int i=0;i<=m;++i)cout<<ans[i]<<' '; cout<<'\n'; if(k<cnt)cout<<"Unhappy! "<<cnt-k<<'\n'; }
I. 野兽节拍
题意:给一个字符串
注意到所有模式串的消除次数之和是
消除有两种情况,一是本身就有模式串作为子串,二是之前的消除产生了连锁反应。连锁反应只可能在上次消除的周围三个位置产生。
预处理每个模式串初始的出现位置,用链表维护当前的字符串。维护一个匹配指针,每次消除更新链表的同时枚举当前指针后面的三个位置,如果没找到模式串就说明这个位置的连锁反应已经结束了,直接把匹配指针移到下一个初始位置。
总复杂度
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pii; const int N=1e6+5; int n,pre[N],nxt[N]; vector<pii> buf; vector<int> pos[26][26][26]; void ins(int x,int y){ pre[x]=y,nxt[x]=nxt[y]; pre[nxt[y]]=x,nxt[y]=x; } void del(int x){ buf.push_back(pii(x,pre[x])); pre[nxt[x]]=pre[x]; nxt[pre[x]]=nxt[x]; } string a; int ans; vector<int> anss; int calc(int x,int y,int z){ int i=pos[x][y][z][0],j=0,m=pos[x][y][z].size(),res=0; while(j<m){ bool fl=0; for(int k=0;k<3&&i<=n;++k){ if(pre[i]>0&&pre[pre[i]]>0&&a[i]==z&&a[pre[i]]==y&&a[pre[pre[i]]]==x){ fl=1,i=nxt[i],++res; del(pre[i]),del(pre[i]),del(pre[i]); break; } i=nxt[i]; } if(!fl){ while(j<m&&pos[x][y][z][j]<i)++j; if(j<m)i=pos[x][y][z][j]; } } for(int i=buf.size()-1;i>=0;--i)ins(buf[i].first,buf[i].second); buf.clear(); return res; } int main(){ ios::sync_with_stdio(0);cin.tie(0); cin>>n>>a,a=" "+a; for(int i=1;i<=n;++i)a[i]-='a'; for(int i=0;i<=n+1;++i)pre[i]=i-1,nxt[i]=i+1; for(int i=3;i<=n;++i)pos[a[i-2]][a[i-1]][a[i]].push_back(i); for(int i=0;i<26;++i) for(int j=0;j<26;++j) for(int k=0;k<26;++k)if(pos[i][j][k].size()){ int t=calc(i,j,k); if(t>ans)ans=t,anss={i,j,k}; } cout<<ans<<'\n'<<char(anss[0]+'a')<<char(anss[1]+'a')<<char(anss[2]+'a')<<'\n'; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧