比赛地址传送门
A. Rudolf and the Ticket
题目大意:
给定两个数组和一个 k,要求从两个数组中各选一个数求和不大于 k,有多少种方案
思路:
维护一个数组 f[i] 代表小于等于 i 的数字的数量,遍历另一个数组,对于每个数字 j,答案加上 f[k - j]
void solve()
{int n,m,k;cin>>n>>m>>k;vector<int> a(n),b(m);vector<int> f(k+1);for(auto &i: a) {cin>>i;}for(auto &i: b) {cin>>i;}sort(b.begin(),b.end());for(int i=1,j=0;i<=k;i++) {// i-per number j-idxf[i]+=f[i-1];while(j<m&&b[j]==i) f[i]++,j++;// cout<<i<<' '<<f[i]<<'\n';}ll ans=0;for(auto temp: a) {if(temp>=k) continue;ans+=(f[k-temp]);}cout<<ans<<'\n';
}
B. Rudolf and 121
题目大意:
给定一个数组,对于其中长度为 3 的连续子段 a i − 1 a_{i-1} ai−1、 a i a_{i} ai、 a i + 1 a_{i+1} ai+1,可以进行如下操作:中间的数减二,两边的数减一,问是否能够将数组全部变为 0
思路:
不难发现对于数组两头的数只能进行减一操作
void solve()
{int n;cin>>n;vector<int> v(n);for(auto &i: v) {cin>>i;}bool succ=true;for(int i=n-1;i>=2;i--) {int _now=v[i];if(_now<0) break;v[i]-=_now,v[i-1]-=2*_now,v[i-2]-=_now;}for(auto temp:v) {succ=succ&&temp==0;}cout<<(succ?"Yes":"No")<<'\n';
}
C. Rudolf and the Ugly String
题目大意:
给定一个字符串,可以任意删除字符,求字符串中不含有 “map” 与 “pie” 的删除字符的最少个数
思路:
- 对于 map 或者 pie 单独出现,只需要删除中间的字符
- 对于 mapie 的情况只需要删除 p 即可
void solve()
{int n;string line;cin>>n>>line;ll ans=0;for(int i=0;i<(ll)line.length()-2;i++) {string temp=line.substr(i,3);if(i+5<=line.length()&&line.substr(i,5)=="mapie") ans++,i+=4;else if(temp=="map"||temp=="pie") ans++,i+=2;}cout<<ans<<'\n';
}
D. Rudolf and the Ball Game
题目大意:
有一排围成一圈的桌子,一个桌子上放有一张卡片,已知卡片的移动信息:移动的方向(顺时针、逆时针、未知)与移动距离,求移动 m 次后卡片可能在的位置
思路:
只需要用dp维护一下每一轮有哪些桌子可能被放上卡片即可
与牛客小白周赛中的 “我不是大富翁” 很像
void solve()
{int n,m,x;cin>>n>>m>>x;vector f(m+1,vector<int>(n));f[0][x-1]=1;for(int j=1;j<=m;j++) {int x;char y;cin>>x>>y;for(int i=0;i<n;i++) {if(y!='1'&&f[j-1][(i-x+n)%n]) f[j][i]=1;if(y!='0'&&f[j-1][(i+x)%n]) f[j][i]=1;}}vector<int> ans;for(int i=0;i<n;i++) {if(f[m][i]) ans.push_back(i+1);}cout<<ans.size()<<'\n';for(auto temp: ans) {cout<<temp<<' ';}cout<<'\n';
}
E. Rudolf and k Bridges
题目大意:
给出一条河的俯视图(左右为两岸),每个数字代表此位置河的深度,同时代表了在此处建立桥柱的花费(此处河的深度+1),要求桥柱间距不能超过 d,两个岸边必须有桥柱,求在连续 k 行上建立桥的最小花费是多少
思路:
注意是连续k行!!! 哭死了/(ㄒoㄒ)/~~
使用dp[i] 维护 “i 列之前的桥柱已经建好的情况下在 i 处建立桥柱的最小花费”,不难发现需要用 dp[i - d - 1] 到 dp[i - 1] 中的最小值来更新dp[i],可以用单调队列优化
void solve()
{int n,m,k,d;cin>>n>>m>>k>>d;vector mp(n,vector<int>(m));for(auto &i: mp) {for(auto &j: i) {cin>>j;}}function<ll(int)> check=[&](int row) {vector<ll> f(m);deque<int> q;f[0]=1ll,q.push_back(0);for(int i=1;i<m;i++) {f[i]=f[q.front()]+mp[row][i]+1;while(!q.empty()&&f[q.back()]>=f[i]) q.pop_back();q.push_back(i);while(i-q.front()>d) q.pop_front();}return f[m-1];};vector<ll> ans;for(int i=0;i<n;i++) {ans.push_back(check(i));if(i) ans[i]+=ans[i-1];}ll result=ans[k-1];for(int i=k;i<n;i++) {result=min(result,ans[i]-ans[i-k]);}cout<<result<<'\n';
}
F. Rudolf and Imbalance
题目大意:
给出三个数组a、b、c,要求在b、c中分别选择两个数插入 a(排好序的) 中,求使得 a 中连续两个相邻元素的差的最大值的最小值为多少
思路:
大佬题解
如果数组 a 中有两个最大间距,那么无解,直接输出这个最大间距就行,否则二分查找可以填在这个间距中的数字,对于数组 b 从小到大排序,数组 c 从大到小排序,使用双指针,当 b 中的元素固定不变时,c 中选择的元素越靠后则两数和越小。
void solve()
{int n,m,k;cin>>n>>m>>k;vector<ll> a(n),b(m),c(k);set<int> sum;for(auto &i: a) cin>>i;for(auto &i: b) cin>>i;for(auto &i: c) cin>>i;ll _large=0,_seclarge=0,_pos=0;for(int i=1;i<n;i++) {if(a[i]-a[i-1]>_large) {_pos=i-1;_seclarge=_large;_large=a[i]-a[i-1];} else {_seclarge=max(_seclarge,(ll)a[i]-a[i-1]);}}if(_large==_seclarge) {cout<<_large<<'\n';return;}sort(b.begin(),b.end());sort(c.begin(),c.end(),[](int a,int b){return a>b;});auto check=[&](ll mid)->bool{for(int _pb=0,_pc=0;_pb<m;_pb++) {// int _pc=0;while(_pc<k&&b[_pb]+c[_pc]>a[_pos+1]) _pc++;ll mn;while(_pc<k&&b[_pb]+c[_pc]>(a[_pos+1]+a[_pos]>>1)) {ll res=b[_pb]+c[_pc];mn=max(abs(res-a[_pos]),abs(res-a[_pos+1]));if(mn<=mid) return true;_pc++;}if(_pc<k&&b[_pb]+c[_pc]>=a[_pos]&&b[_pb]+c[_pc]<=a[_pos+1]) {ll res=b[_pb]+c[_pc];mn=max(abs(res-a[_pos]),abs(res-a[_pos+1]));if(mn<=mid) return true;}}return false;};ll l=0,r=_large;while(l<r) {ll mid=l+r>>1;if(check(mid)) r=mid;else l=mid+1;}cout<<max(r,_seclarge)<<'\n';
}
G. Rudolf and Subway
题目大意:
给出一个图,其中边带颜色,求从给定起点到终点最少需要经过几种颜色
思路
对于给出的每条边的点与颜色,为颜色建一个虚拟点(类似缩点),从点到虚拟点的代价为 1,从虚拟点到点的代价为 0,跑最短路即可
int check(int x)
{return x+200010;
}
void solve()
{int n,m;cin>>n>>m;unordered_map<int,vector<pii>> mp;unordered_map<int,int> _dist;for(int i=1;i<=m;i++) {int a,b,c;cin>>a>>b>>c;mp[a].push_back({check(c),1});mp[b].push_back({check(c),1});mp[check(c)].push_back({a,0});mp[check(c)].push_back({b,0});_dist[a]=_dist[b]=1e9,_dist[check(c)]=1e9;}int d,e;cin>>d>>e;_dist[d]=0;auto dijk=[&]()->int{priority_queue<pii,vector<pii>,greater<>> q;q.push({0,d});while(!q.empty()) {auto [dis,u]=q.top();q.pop();// cout<<u<<'\n';for(auto v: mp[u]) {auto [x,w]=v;if(_dist[x]>dis+w) {_dist[x]=dis+w;q.push({_dist[x],x});}}}return _dist[e];};cout<<dijk()<<'\n';
}