Namomo Summer Camp 23 Day 1
A - Amusement Arcade
题意:有
思路:我们可以发现一个规律,当第一个人的位置确定了,其他人的位置也都是确定的。那么第一个人选了一个位置,这个人两边就转化为第一个人坐第一个位置(端点)的问题。对于这个第一次坐在第一个位置的子问题,我们再去考虑。如果第一个人坐在第一个,下一个肯定坐在另一个端点了,在下一个坐在它们的中点,以此类推,都是在中点位置。
于是,进一步观察,当第一个位置确定后,它两边都是2的幂次的时候是可行的。那么只用在
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int mod = 1e9 + 7; const int N = 2e5 + 10; ll qmi(ll a, ll b) { ll ans = 1; while(b) { if(b & 1) ans = ans * a ; a = a * a ; b >>= 1; } return ans; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr); ll n; cin>>n; if(n==1||n==3){ cout<<1<<"\n"; return 0; } for(int i = 0;i<=90;i++) { for(int j = 0;j<=90;j++) { if(qmi(2,i)+qmi(2,j)+1==n) { cout<<qmi(2,i)+1<<"\n"; return 0; } } } cout<<"impossible\n"; }
B - Brexiting and Brentering
题意:找到最后一个元音
思路:按题意模拟即可。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int mod = 1e9 + 7; const int N = 2e5 + 10; int main() { ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr); string s; cin>>s; int len = s.size(); int last = -1; for(int i = len-1;i>=0;i--) { if(s[i]=='a'||s[i]=='e'||s[i]=='i'||s[i]=='o'||s[i]=='u') { last = i; break; } } if(last == -1) cout<<s<<"\n"; else { for(int i = 0;i<=last;i++) cout<<s[i]; cout<<"ntry\n"; } return 0; }
C - Card Trading
题意:告诉你
思路:因为对于一个报价,小于等于它的我们可以买入,大于等于它的我们可以卖出。那么我们可以先以价格为第一关键字进行
注意:可能会有精度问题,我们先变成
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int mod = 1e9 + 7; const int N = 2e5 + 10; int n; vector<array<ll,3>>a; ll buy[N],sale[N]; int main() { //ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr); cin>>n; for(int i = 1;i <= n; i++) { double p; ll x,y; cin>>p>>x>>y; // p*=100ll; ll pp = p * 100ll; a.push_back({pp,x,y}); } a.push_back({0,0,0}); sort(a.begin(), a.end()); for(int i = 1;i <= n; i++) { buy[i] = buy[i-1]+a[i][2]; } for(int i = n;i >= 1; i--) { sale[i] = sale[i+1]+a[i][1]; } // for(int i = 1;i <= n;i++) // cout<<buy[i]<<" "<<sale[i]<<"\n"; ll ans = 0,pos = -1; for(int i = 1;i <= n;i++) { if(ans<min(buy[i],sale[i])*a[i][0]) ans = min(buy[i],sale[i])*a[i][0],pos = i; } if(pos==-1)cout<<"impossible\n"; else { ll t1 = a[pos][0],t2 = ans; string s1 = to_string(t1),s2 = to_string(t2); int len1 = s1.size(),len2 = s2.size(); cout<<s1.substr(0,max(0,len1-2))<<"."<<s1.substr(len1-2,len1)<<" "; cout<<s2.substr(0,max(0,len2-2))<<"."<<s2.substr(len2-2,len2)<<" "; } return 0; } /* 6 2.85 14 0 4.50 0 1 5.26 3 3 6.17 1 0 14.78 0 2 21.04 1 0 5 12.00 0 3 11.99 2 0 11.98 5 0 10.00 1 0 12.01 0 6 */
D - Excursion to Porvoo
题意:有
思路:一开始我的思路是,我考虑,对于大的承重加入承重小于它的边是没有意义的,所以我读入边之后,按照重量排序。然后询问也离线读入然后按重量从大到小排序。每次加的边是比当前询问重量大的边到之前加过的边为止。因为是从按照重量大到小排序的,那么之前可以用的边现在也一定可以用,只需要考虑多出来的边能不能更新以前的边即可。然后。。得到了一个
以下是本人写的依托答辩:
#include <bits/stdc++.h> using namespace std; #define int long long typedef long long ll; const int mod = 1e9 + 7; const int N = 1e6 + 10; //vector<array<int,3>>e[N]; set<array<int,3>>weight[N]; set<int>s; int ans[N]; vector<pair<int,int>>que; int cnt,a[N]; int n,m,q; int dist[N]; map<pair<int,int>,int>len; bool cmp(pair<int,int> x,pair<int,int> y) { return x.first>y.first; } signed main() { ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr); cin>>n>>m; int maxc = 0; vector<int>s; for(int i = 1;i <= m;i++) { int x,d,c; cin>>x>>d>>c; if(len[{x,c}]==0)len[{x,c}] = 1e9; len[{x,c}] = min(len[{x,c}],d); // e[x].push_back({x+1,d,c}); maxc = max(maxc,c); weight[c].insert({x,x+1,len[{x,c}]}); s.push_back(c); } sort(s.begin(),s.end()); s.erase(unique(s.begin(),s.end()),s.end()); for(auto x:s) a[++cnt] = x; cin>>q; for(int i = 1;i<=q;i++) { int w; cin>>w; que.push_back({w,i}); } sort(que.begin(), que.end(),cmp); int last = cnt; ll ret = 0; int cnt = 0; for(auto [w,i]:que) { if(w>maxc){ ans[i] = -1; continue; } int pos = lower_bound(s.begin(),s.end(),w)-s.begin(); pos++; //cout<<"pos = "<<pos<<" last = "<<last<<"\n"; for(int j = pos;j<=last;j++) { // cout<<"a[j] = "<<a[j]<<"\n"; for(auto [x,y,d]:weight[a[j]]) { //cout<<"x = "<<x<<" y = "<<y<<" d = "<<d<<"\n"; int t = dist[x]; if(t==0||t>d) { dist[x] += (d-t),ret += (d-t); if(t==0)cnt++; } } } last = pos; if(cnt==n-1) ans[i] = ret; else ans[i] = -1; } for(int i = 1;i<=q;i++) { if(ans[i]==-1)cout<<"impossible\n"; else cout<<ans[i]<<"\n"; } return 0; }
好啦,那么正解是什么呢?与k同学一番讨论
首先,之前的写法问题出在询问部分,最坏的情况可能是
之后就是读入询问(离线),用
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int mod = 1e9 + 7; const int N = 1e5 + 10; int n,m,q; vector<pair<int,int>>e[N]; set<pair<int,int>>que; set<pair<int,int>>edge; int last[N],ans[N]; int dist[N]; vector<int> suf[N]; int main() { ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr); cin>>n>>m; for(int i = 1;i <= m; i++) { int x,d,c; cin>>x>>d>>c; e[x].push_back({c,d}); } for(int i = 1;i < n ; i++) sort(e[i].begin(),e[i].end()); for(int i = 1;i < n; i++) { int sz = e[i].size(); suf[i].resize(sz + 2); suf[i][sz-1] = sz-1; for(int j = sz-2;j>=0;j--) { int c = e[i][j].first, d = e[i][j].second; int d2 = e[i][suf[i][j+1]].first,c2 = e[i][suf[i][j+1]].second; if(d<d2&&c>=c2)suf[i][j] = j; else suf[i][j] = suf[i][j+1]; } } // for(int i = 1;i < n; i++) // { // int sz = e[i].size(); // for(int j = 0;j<sz;j++) // { // cout<<suf[i][j]<<" "; // } // cout<<"\n"; // } cin>>q; for(int i = 1;i <= q; i++) { int w; cin>>w; que.insert({w,i}); } for(int i = 1;i < n; i++) { edge.insert({0,i}); } bool flag = false; ll ret = 0; for(auto [w,i]:que) { // cout<<"w = "<<w<<" i = "<<i<<"\n"; if(flag) { ans[i] = -1; continue; } bool smaller = false; bool ok = false; while(edge.begin()->first<w) { // cout<<"edge.begin()->first = "<<edge.begin()->first<<"\n"; smaller = true; int pos = edge.begin()->second; int c = edge.begin()->first; int sz = e[pos].size(); int n_c = c,n_d = 1e9; int l_d = dist[pos]; ok = false; // cout<<"pos = "<<pos<<" "<<"last[pos] = "<<last[pos]<<"\n"; // cout<<"c = "<<c<<" n_c = "<<n_c<<" n_d = "<<n_d<<" l_d = "<<l_d<<"\n"; // cout<<"sz = "<<sz<<"\n"; for(int j = last[pos];j<sz;j++) { //cout<<"e[pos][j].first = "<<e[pos][j].first<<" e[pos][j].second = "<<e[pos][j].second<<"\n"; if(e[pos][j].first>=w) { ok = true; if(n_d>=e[pos][j].second) n_c = e[pos][j].first,n_d = e[pos][j].second,last[pos] = j; // cout<<" n_c = "<<n_c<<" n_d = "<<n_d<<"\n"; } } if(ok) { // cout<<" n_d = "<<n_d<<" l_d = "<<l_d<<"\n"; ret = ret + n_d - l_d; ans[i] = ret; //cout<<"ret = "<<ret<<"\n"; dist[pos] = n_d; edge.erase(edge.begin()); edge.insert({n_c,pos}); } else break; } if(smaller&&!ok){ ans[i] = -1; flag = true; } if(!smaller)ans[i] = ret; } for(int i = 1;i <= q;i++) { if(ans[i]==-1)cout<<"impossible\n"; else cout<<ans[i]<<"\n"; } return 0; }
H - Looking for Waldo
题意:让你找到一个最小的矩形(平行于坐标轴)去框住包含
思路:当时写的时候,kk提示我之前写个的一个
// AK one more times #include <bits/stdc++.h> using namespace std; typedef long long ll; const int mod = 1e9 + 7; const int N = 2e5 + 10; int n,m; void solve() { cin>>n>>m; int a[n+10][m+10]; int cnt[6][n+10][m+10]; for(int i = 1;i<=5;i++) for(int j = 0;j<=n;j++) for(int k = 0;k<=m;k++) cnt[i][j][k] = 0,a[j][k] = 0; for(int i = 1;i<=n;i++) { for(int j = 1;j<=m;j++) { char c;cin>>c; if(c=='W')a[i][j] = 1; else if(c=='A')a[i][j] = 2; else if(c=='L')a[i][j] = 3; else if(c=='D')a[i][j] = 4; else if(c=='O')a[i][j] = 5; } } for(int i = 1;i<=5;i++) { for(int j = 1;j<=n;j++) { for(int k = 1;k<=m;k++) { cnt[i][j][k] = cnt[i][j-1][k]+cnt[i][j][k-1]-cnt[i][j-1][k-1]; cnt[i][j][k] += (a[j][k]==i); } } } // for(int j = 1;j<=n;j++) // { // for(int k = 1;k<=m;k++) // { // cout<<a[j][k]<<" "; // } // cout<<endl; // } // cout<<endl; // for(int i = 1;i<=5;i++) // { // for(int j = 1;j<=n;j++) // { // for(int k = 1;k<=m;k++) // { // cout<<cnt[i][j][k]<<" "; // } // cout<<endl; // } // cout<<endl; // } int ans = 1e9; for(int x = 1;x<=n;x++) { for(int y = 1;y<=m;y++) { for(int w = 1;w<=n-x+1;w++) { int l = 1,r = m-y+1; while(l<=r) { int mid = (l+r)>>1; // cout<<"w = "<<w<<" h = "<<mid<<endl; //bool ok1 = false,ok2 = false,ok3 = false,ok4 = false,ok5 = false; // for(int i = x;i < x+w;i++) // { // for(int j = y;j < y+mid; j++) // { // if(a[i][j]=='W')ok1 = true; // if(a[i][j]=='A')ok2 = true; // if(a[i][j]=='L')ok3 = true; // if(a[i][j]=='D')ok4 = true; // if(a[i][j]=='O')ok5 = true; // } // } int ok = 0; for(int i = 1;i<= 5;i++) { if(cnt[i][x+w-1][y+mid-1]-cnt[i][x-1][y+mid-1]-cnt[i][x+w-1][y-1]+cnt[i][x-1][y-1])ok++; } if(ok==5){ r = mid-1; // cout<<"r = "<<r<<endl; ans = min(ans,(r+1)*w); } else l = mid+1; } } } } if(ans==1e9)cout<<"impossible\n"; else cout<<ans<<"\n"; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr); solve(); return 0; }
I - Monty's Hall
题意:有
思路:是个概率题,写完后看大家说是三门问题来的。考虑第一次中的概率:
再考虑我们要不要换。假设我们换
最终概率就是:
我们只需要枚举
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int mod = 1e9 + 7; const int N = 2e5 + 10; int main() { ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr); double d,s,e; cin>>d>>s>>e; double ans = 0; for(int l = 0;l<=min(s,d-s-e);l++) { //cout<<(s-(double)l)/d<<" "<<((d-s)/d)*((double)l*(d-s-e))<<'\n'; ans = max(ans,((s-(double)l)/d)+((d-s)/d*((double)l/(d-s-e)))); } printf("%.10lf\n",ans); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix