2024icpc上海区域赛(ICBG)
题目链接:The 2024 ICPC Asia Shanghai Regional Contest - 比赛主页 - 比赛 - QOJ.ac
I. In Search of the Ultimate Artifact
思路
从所有非0的里面每次选前k个最大的合成1个,要是不够k个则输出当前最大值即可
代码
void solve(){int n,k;cin>>n>>k;priority_queue<int> q;int mx=0;for(int i=1;i<=n;i++){int x;cin>>x;if(x==0) continue;q.push(x);mx=max(mx,x);}if(q.size()<k){cout<<mx%mod<<"\n";return;}int ans=q.top();q.pop();while(q.size()>=k-1){for(int i=1;i<k;i++){ans=(ans*q.top())%mod;q.pop();}}cout<<ans<<"\n";
}C. Conquer the Multiples
思路
对于x来说如果每次都选择1*x也就是脚底下的位置的话,那么数量的奇偶就决定了输赢,知道这个后,再考虑进去如果选择了2*x或者m*x,如果x为偶数的话删去m*x那么在x与m*x之间就剩余了奇数个数量的数,同理x为奇数的话会剩余偶数数量的数,肯定能够迫使后手只能选择脚底下的数,知道了这个原理后分类讨论即可
代码
void solve(){int l,r;cin>>l>>r;int x=2*l;if(x>r){int cnt=r-l+1;if(cnt%2){cout<<"Alice\n";}else{cout<<"Bob\n";}}else{if(l%2){cout<<"Alice\n";}else{if((l+1)*2<=r){cout<<"Bob\n";}else{int cnt=r-l+1;if(cnt%2){cout<<"Alice\n";}else{cout<<"Bob\n";}}}}
}B. Basic Graph Algorithm
思路
用给定序列跑dfs模拟过程即可,如果可以到达下一个节点则继续递归,否则的话就建一条边,继续递归
代码
#include<bits/stdc++.h>
using namespace std;#define vcoistnt ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL); 
#define int long long
#define vi vector<int>
#define vb vector<bool>
typedef pair<int,int> pll;const int N=2e5+10;
const int inf=1e18;
const int mod=998244353;void solve(){int n,m;cin>>n>>m;vector<vector<int>> e(n+1);set<int> s[n+1];for(int i=1;i<=m;i++){int u,v;cin>>u>>v;e[u].push_back(v);e[v].push_back(u);s[u].insert(v);s[v].insert(u);}vector<int> p(n+1);for(int i=1;i<=n;i++){cin>>p[i];}int id=1;vector<pll> ans;function<void(int)> dfs=[&](int u)->void{for(int v:e[u]){s[v].erase(u);}while(s[u].size()&&id<=n){if(s[u].count(p[id])){s[u].erase(p[id]);++id;dfs(p[id-1]);}else{ans.push_back({u,p[id]});++id;dfs(p[id-1]);}}};while(id<=n){++id;dfs(p[id-1]);}cout<<ans.size()<<"\n";for(auto [x,y]:ans){cout<<x<<" "<<y<<"\n";}
}
signed main() {vcoistntcout<<fixed<<setprecision(2);int _=1;// cin>>_;while(_--) solve();return 0;
}G. Geometry Task
思路
二分答案中位数,然后看最优的选择中有是否>=x的数要大于等于(n+1)/2个,若大于则说明中位数至少是x
对c进行排序,关于最优的选择,对于每条直线来说
斜率若为正,则可以在c中找到若想其>=x的最小位置,可以选择的区间为【L,n】
斜率若为负,则可以在c中找到若想其>=x的最大位置,可以选择的区间为【1,L】
最后我们将统计出来的区间排序,然后贪心地选择即可,看是否>=(n+1)/2
代码
#include<bits/stdc++.h>
using namespace std;#define vcoistnt ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL); 
#define int long long
#define vi vector<int>
#define vb vector<bool>
typedef pair<int,int> pll;void solve(){int n;cin>>n;vector<int> a(n+1),b(n+1);vector<int> c(n+1);for(int i=1;i<=n;i++) cin>>a[i];for(int i=1;i<=n;i++) cin>>b[i];for(int i=1;i<=n;i++) cin>>c[i];sort(c.begin()+1,c.begin()+1+n);auto check=[&](int x)->bool{vector<pll> q;for(int i=1;i<=n;i++){if(a[i]>0){int l=1,r=n;int ans=1;while(l<=r){int mid=l+r>>1;if(c[mid]*a[i]+b[i]>=x){ans=mid;r=mid-1;}else{l=mid+1;}}if(c[ans]*a[i]+b[i]>=x) q.push_back({ans,n});}else{int l=1,r=n;int ans=1;while(l<=r){int mid=l+r>>1;if(c[mid]*a[i]+b[i]>=x){ans=mid;l=mid+1;}else{r=mid-1;}}if(c[ans]*a[i]+b[i]>=x) q.push_back({1,ans});}}sort(q.begin(),q.end());int cnt=0,m=q.size();for(int i=1,j=0;i<=n;i++){while(j<m&&q[j].second<i) j++;if(j<m&&q[j].first<=i){cnt++;j++;}}return cnt>=(n+1)/2;};int l=LONG_LONG_MIN;int r=LONG_LONG_MAX;int ans=0;while(l<=r){int mid=(l+r)>>1;if(check(mid)){ans=mid;l=mid+1;}else{r=mid-1;}}cout<<ans<<"\n";
}
signed main() {vcoistntcout<<fixed<<setprecision(2);int _=1;cin>>_;while(_--) solve();return 0;
}