The 2022 ICPC Asia Xian Regional Contest 前六题
The 2022 ICPC Asia Xian Regional Contest
签到题题解 CFJ#
J. Strange Sum#
易证最多只能选两个,从大到小排序后
void solve(){
cin>>n;
vector<ll>a(n+1);
for(int i=1;i<=n;i++)cin>>a[i];
sort(a.begin()+1,a.end());
ll ans=a[n]+a[n-1];
ans=max(ans,a[n]);
if(ans<0)cout<<0;
else cout<<ans;
}
C. Clone Ranran#
先出题再克隆一定不优,所以枚举克隆几次,再出题,时间复杂度
ll f[32];
void pre(){
f[0] = 1;
for(int i=1;i<32;i++){
f[i]=f[i-1]*2;
}
}
void solve(){
ll a,b,c;
cin >> a >> b >> c;
ll ans = 1e18;
for(int i=0;i<32;i++){
ll cnt = f[i];
ll tans = ((c+cnt-1)/cnt)*b+i*a;
ans = min(ans,tans);
}
cout << ans << '\n';
}
F Hotel#
主要注意一下同一个房间的同性别的也可以住俩房间
string s[1010];
void solve(){
int n,c1,c2;
cin >> n >> c1 >> c2;
for(int i=0;i<n;i++){
cin >> s[i];
}
if(c1 * 2 <= c2){
cout << 3 * n * c1;
return;
}
int ans = 0;
for(int i=0;i<n;i++){
if(s[i][0]==s[i][1] || s[i][0]==s[i][2] || s[i][1] == s[i][2]){
ans += min(c1,c2)+c2;
}else{
ans += 3*min(c1,c2);
}
}
cout<<ans;
}
G. Perfect Word#
题意#
给若干串,要求构造一个串,这个串的所有子串都在给的串中出现
思路#
我感觉有点巧妙
先按长度排好序,每次枚举给的串
注意,如果
也就是说对
给定的所有串长度是
代码#
#define ll long long
#define inf INT_MAX
#define INF LONG_LONG_MAX
#define endl '\n'
const int N = 1e5 + 5;
string s[N];
set<string>hsh; // 一开始写哈希的,写完调了一下被队友发现根本不用多此一举
void solve(){
int n;
cin >> n;
for(int i=0;i<n;i++){
cin >> s[i];
}
sort(s,s+n,[](string &s1,string &s2){
return s1.length() < s2.length();
});
int ans = 1;
for(int i = 0; i < n; i++){
int len = s[i].length();
if(len == 1)hsh.insert(s[i]);
else{
if(hsh.find(s[i].substr(0,len-1)) != hsh.end() && hsh.find(s[i].substr(1,len-1)) != hsh.end()){
ans = s[i].length();
hsh.insert(s[i]);
}
}
}
cout << ans << endl;
}
L. Tree#
题意#
给一颗树,分成若干个点集,要求每个点集内任意两个点满足以下两个要求之一
- 对于所有
, , 要么u在v的子树中,要么v在u的子树内 - 对于所有
, , 同时满足uv不在相互的子树中
思路#
分析一下就是,要么点集内所有的点组成一条链,要么是点集内没有任何两个点的LCA同样在点集内
从一开始的考虑要么是叶子结点的数量,要么是层数
到把链缩成点后的要么是叶子结点要么是层数
到最后的,每次把所有叶子结点划分为一个点集,然后从图中删除
大致是这样,具体实现还得看队友啊
代码#
#define ll long long
const int N = 1000005;
int f[N], in[N];
void solve(){
int n;
cin>>n;
for(int i = 1;i<=n;++i)
in[i] = 0;
for(int i = 2;i<=n;++i){
cin>>f[i];
++in[f[i]];
}
vector<int> vec1, vec2, *cur = &vec1, *next = &vec2;
for(int i = 1;i<=n;++i){
if(!in[i])
cur->push_back(i);
}
int ans = cur->size();
int layer = 0;
do{
++layer;
for(auto iter:*cur){
--in[f[iter]];
if(!in[f[iter]] && f[iter])
next->push_back(f[iter]);
}
swap(cur, next);
ans = min(ans,(int)(layer+cur->size()));
next->clear();
}while(!cur->empty());
cout<<ans<<endl;
}
int t=1;
int main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>t;
while(t--){
solve();
}
return 0;
}
E. Find Maximum#
题意#
计算
思路#
发现 f(n) 是 n 在三进制下的数码和加上数位个数
那么取R的三进制,然后枚举每一位,当前位-1,当前位后面的全变为2
相当于考虑尽可能多的2,最高就80位
队友太给力啦,最后一小时调出来了
代码#
#define ll long long
ll l,r;
ll ksm(ll x,ll y){
ll res=1;
while (y>0)
{
if(y&1)res=res*x;
x=x*x;
y=y/2;
}
return res;
}
ll f(ll x){
if(x == 0)return 1;
if(x % 3 == 0)return f(x/3)+1;
return f(x-1)+1;
}
vector<ll> three(ll x){
vector<ll>y;
while (x>0)
{
y.push_back(x%3);
x/=3;
}
return y;
}
ll ten(vector<ll> x){
ll y=0;
for(int i=0;i<x.size();i++){
y+=ksm(3,i)*x[i];
}
return y;
}
void solve(){
cin>>l>>r;
vector<ll>rr=three(r);
ll ans=0;
ans=max(f(l),f(r));
for(int i=rr.size()-1;i>=0;i--){
vector<ll>temp=rr;
if(rr[i]==1&&i!=rr.size()-1){
temp[i]=0;
for(int j=i-1;j>=0;j--){
temp[j]=2;
}
if(ten(temp)>=l){
ans=max(ans,f(ten(temp)));
break;
}
}
else if(rr[i]==2){
temp[i]=1;
for(int j=i-1;j>=0;j--){
temp[j]=2;
}
if(ten(temp)>=l){
ans=max(ans,f(ten(temp)));
break;
}
}
}
for(int i=0;i<rr.size()-1;i++)rr[i]=2;
rr[rr.size()-1]=0;
if(ten(rr)>=l)ans=max(ans,f(ten(rr)));
cout<<ans<<'\n';
}
总结#
这场的,铜牌题,还是看思维多一些,而且题的梯度安排比较接近,做的很舒适
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!