Gym 104172 The 2023 ICPC Asia Hong Kong Regional Programming Contest (The 1st Universal Cup, Stage 2:Hong Kong)
A. TreeScript
令
如果
若
令
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int N=200005;
int n;
int p[N];
vector<int>G[N];
int f[N];
void dfs(int u,int father)
{
int cnt=0,mx=0;
for(int v:G[u])
{
if(v==father) continue;
dfs(v,u);
if(f[v]>mx) mx=f[v],cnt=1;
else if(f[v]==mx) cnt++;
}
if(mx==0) f[u]=1;
else if(cnt>1) f[u]=mx+1;
else f[u]=mx;
return;
}
void solve()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>p[i];
for(int i=1;i<=n;i++)
G[i].clear();
for(int i=2;i<=n;i++)
G[p[i]].emplace_back(i),G[i].emplace_back(p[i]);
dfs(1,0);
cout<<f[1]<<"\n";
return;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
int T;
cin>>T;
while(T--)
solve();
return 0;
}
B. Big Picture
黑色格子的连通块数量肯定为
可以发现,一个白色连通块只会有一个点右边和下面都是黑色的,计算每个格子作为这个点的概率相加即可。
#include<iostream>
#include<cstdio>
using namespace std;
const int N=1005;
const int MOD=998244353;
int n,m;
int p[N][N],q[N][N];
int sp[N][N],sq[N][N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>p[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>q[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
sp[i][j]=(sp[i][j-1]+p[i][j])%MOD;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
sq[i][j]=(sq[i-1][j]+q[i][j])%MOD;
int ans=2;
for(int i=1;i<n;i++)
for(int j=1;j<m;j++)
{
int a=(long long)sp[i][j-1]*sq[i-1][j]%MOD,b=(long long)(1-sp[i+1][j-1]+MOD)*(1-sq[i-1][j+1]+MOD)%MOD;
ans=(ans+(long long)a*b)%MOD;
}
cout<<ans;
return 0;
}
C. Painting Grid
当
不妨令
我们可以通过前
剩下的行直接暴力在上一个行
#include<iostream>
#include<cstdio>
#include<map>
#include<numeric>
#include<random>
#include<chrono>
#include<algorithm>
using namespace std;
const int N=1005;
int n,m;
string a[N];
void solve()
{
cin>>n>>m;
if(n*m%2==1)
{
cout<<"NO\n";
return;
}
if(n<=30&&(1<<n)<m)
{
cout<<"NO\n";
return;
}
if(m<=30&&(1<<m)<n)
{
cout<<"NO\n";
return;
}
bool rev=false;
if(m%2!=0) rev=true,swap(n,m);
for(int i=1;i<=n;i++)
a[i].resize(m+1);
int k=ceil(log2(m)),v=0;
static bool vis[N*2];
for(int i=0;i<=(1<<k);i++)
vis[i]=false;
auto getstatusrev=[=](int x)
{
return (~x)&((1<<k)-1);
};
int cur=0;
for(int j=1;j<=m;j+=2)
{
int val;
while(cur<k&&(vis[1<<cur]||vis[getstatusrev(1<<cur)])) cur++;
if(cur<k) val=1<<cur,cur++;
else
{
while(vis[v]||vis[getstatusrev(v)]) v++;
val=v;
}
vis[val]=vis[getstatusrev(val)]=true;
for(int i=1;i<=k;i++)
a[i][j]=((val>>(i-1))&1)+'0',a[i][j+1]=(((val>>(i-1))&1)^1)+'0';
}
if(k<n)
{
sort(a+1,a+k+1);
map<string,bool>book;
for(int i=1;i<=k;i++)
book[a[i]]=true;
auto getrev=[=](string s)
{
string t;
t.resize(m+1);
for(int i=1;i<=m;i++)
if(s[i]=='1') t[i]='0';
else t[i]='1';
return t;
};
for(int i=k+2;i<=n;i+=2)
{
if(i-2>k)
{
for(int j=1;j<=m;j++)
a[i][j]=a[i-2][j];
bool flag=false;
do
{
a[i][m]++;
for(int j=m;j>=1;j--)
if(a[i][j]=='2')
{
if(j-1>=1) a[i][j-1]++;
else
{
flag=true;
break;
}
a[i][j]='0';
}
else break;
if(flag) break;
}
while(book.count(a[i])||book.count(getrev(a[i])));
if(!flag) a[i-1]=getrev(a[i]);
else
{
for(int j=1;j<=m;j++)
a[i][j]='0';
while(book.count(a[i]))
{
a[i][m]++;
for(int j=m;j>=1;j--)
if(a[i][j]=='2')
{
if(j-1>=1) a[i][j-1]++;
a[i][j]='0';
}
else break;
}
for(int j=1;j<=m;j++)
a[i-1][j]=a[i][j];
do
{
a[i-1][m]++;
for(int j=m;j>=1;j--)
if(a[i-1][j]=='2')
{
if(j-1>=1) a[i-1][j-1]++;
a[i-1][j]='0';
}
else break;
}
while(book.count(a[i-1]));
}
}
else
{
for(int j=1;j<=m;j++)
a[i][j]='0';
while(book.count(a[i])||book.count(getrev(a[i])))
{
a[i][m]++;
for(int j=m;j>=1;j--)
if(a[i][j]=='2')
{
if(j-1>=1) a[i][j-1]++;
a[i][j]='0';
}
else break;
}
a[i-1]=getrev(a[i]);
}
book[a[i]]=book[a[i-1]]=true;
}
if((n-k)%2==1)
{
static int p[N];
static mt19937_64 rnd(chrono::system_clock::now().time_since_epoch().count());
iota(p+1,p+m+1,1);
do
{
shuffle(p+1,p+m+1,rnd);
for(int i=1;i<=m/2;i++)
a[n][p[i]]='1';
for(int i=m/2+1;i<=m;i++)
a[n][p[i]]='0';
}
while(book.count(a[n]));
}
}
cout<<"YES\n";
if(rev)
{
for(int j=1;j<=m;j++)
{
for(int i=1;i<=n;i++)
cout<<a[i][j];
cout<<"\n";
}
}
else
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
cout<<a[i][j];
cout<<"\n";
}
}
return;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
int T;
cin>>T;
while(T--)
solve();
return 0;
}
D. Shortest Path Query
E. Goose, Goose, DUCK?
可以发现,这个
#include<iostream>
#include<cstdio>
#include<vector>
#include<tuple>
#include<algorithm>
using namespace std;
const int N=1000005;
int n,m,k;
int a[N];
vector<int>pos[N];
vector<tuple<int,int,int>>seg[N];
struct Segment_Tree
{
#define ls i*2
#define rs i*2+1
struct Node
{
int l,r,cnt;
long long sum;
}tree[N*4];
void build(int i,int l,int r)
{
tree[i].l=l,tree[i].r=r,tree[i].cnt=tree[i].sum=0;
if(l==r) return;
int mid=(l+r)/2;
build(ls,l,mid);
build(rs,mid+1,r);
return;
}
void push_up(int i)
{
if(tree[i].cnt) tree[i].sum=tree[i].r-tree[i].l+1;
else tree[i].sum=tree[ls].sum+tree[rs].sum;
return;
}
void modify(int i,int l,int r,int k)
{
if(l<=tree[i].l&&tree[i].r<=r)
{
tree[i].cnt+=k;
if(tree[i].cnt) tree[i].sum=tree[i].r-tree[i].l+1;
else if(tree[i].l==tree[i].r) tree[i].sum=0;
else tree[i].sum=tree[ls].sum+tree[rs].sum;
return;
}
if(l<=tree[ls].r) modify(ls,l,r,k);
if(r>=tree[rs].l) modify(rs,l,r,k);
push_up(i);
return;
}
int query(int i,int l,int r)
{
if(l<=tree[i].l&&tree[i].r<=r) return tree[i].sum;
int res=0;
if(l<=tree[ls].r) res+=query(ls,l,r);
if(r>=tree[rs].l) res+=query(rs,l,r);
return res;
}
#undef ls
#undef rs
}T;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
cin>>n>>k;
for(int i=1;i<=n;i++)
cin>>a[i];
m=*max_element(a+1,a+n+1);
for(int u=1;u<=m;u++)
pos[u].emplace_back(0);
for(int i=1;i<=n;i++)
pos[a[i]].emplace_back(i);
for(int u=1;u<=m;u++)
{
pos[u].emplace_back(n+1);
for(int i=1;i<(int)pos[u].size();i++)
if(i+k<(int)pos[u].size())
{
int ll=pos[u][i-1]+1,lr=pos[u][i];
int rl=pos[u][i+k-1],rr=pos[u][i+k]-1;
seg[ll].emplace_back(rl,rr,1),seg[lr+1].emplace_back(rl,rr,-1);
}
}
T.build(1,1,n);
long long ans=0;
for(int i=1;i<=n;i++)
{
for(auto [l,r,v]:seg[i])
T.modify(1,l,r,v);
ans+=n-i+1-T.query(1,i,n);
}
cout<<ans;
return 0;
}
F. Sum of Numbers
最后肯定是让每段的长度尽可能平均,令
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<vector>
using namespace std;
struct BigInteger
{
static const long long base_=(long long)1e18;
static const int width_=18;
vector<long long> val_;
BigInteger(int num=0)
{
do
{
val_.push_back(num%base_);
num/=base_;
}
while(num);
}
BigInteger(long long num)
{
do
{
val_.push_back(num % base_);
num/=base_;
}
while(num);
}
BigInteger(const string &str)
{
int be=0,en=str.size();
while((en-=width_)>=be)
val_.push_back(stoll(str.substr(en, width_)));
if((en+=width_)>be)
val_.push_back(stoll(str.substr(be,en-be)));
}
BigInteger &operator=(int num)
{
return *this=BigInteger(num);
}
BigInteger &operator=(long long num)
{
return *this=BigInteger(num);
}
BigInteger &operator=(const string &str)
{
return *this=BigInteger(str);
}
bool operator<(const BigInteger &obj)const
{
if(val_.size()!=obj.val_.size()) return val_.size()<obj.val_.size();
for(int i=val_.size()-1;i>=0;i--)
if(val_[i]!=obj.val_[i]) return val_[i]<obj.val_[i];
return false;
}
BigInteger operator+(const BigInteger &obj)const
{
BigInteger result;
int os=max(val_.size(),obj.val_.size());
result.val_.resize(os);
for(int i=0;i<os;i++)
{
long long tmp=result.val_[i];
if(i<(int)val_.size()) tmp+=val_[i];
if(i<(int)obj.val_.size()) tmp+=obj.val_[i];
if(tmp>=base_)
{
tmp-=base_;
if(i+1>=(int)result.val_.size()) result.val_.push_back(0);
result.val_[i+1]++;
}
result.val_[i]=tmp;
}
return result;
}
friend ostream &operator<<(ostream &,const BigInteger &);
};
ostream &operator<<(ostream &out,const BigInteger &obj)
{
out<<obj.val_.back();
for(int i=obj.val_.size()-2;i>=0;i--)
out<<setw(BigInteger::width_)<<setfill('0')<<obj.val_[i];
return out;
}
const int N=200005;
int n,k;
string s;
bool vis[N];
BigInteger dp[N];
void solve()
{
cin>>n>>k;
cin>>s;
for(int i=1;i<=n;i++)
vis[i]=false;
int len=n/(k+1)+2;
for(int t=0;t<=k;t++)
for(int i=n;i>=max(1,n-len*(k-t));i--)
for(int j=max(0,i-len);j<=t*len&&j<i;j++)
if(j==0||vis[j])
{
BigInteger v=dp[j]+s.substr(j,i-j);
if(!vis[i]||v<dp[i]) dp[i]=v,vis[i]=true;
}
cout<<dp[n]<<"\n";
return;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
int T;
cin>>T;
while(T--)
solve();
return 0;
}
G. Paddle Star
H. Another Goose Goose Duck Problem
等待时间肯定越小越好,然后直接算就行。
#include<iostream>
#include<cstdio>
using namespace std;
int l,r,b,k;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
cin>>l>>r>>b>>k;
long long ans=(long long)(l+b-1)/b*b*k;
cout<<ans;
return 0;
}
I. Range Closest Pair of Points Query
J. Dice Game
K. Maximum GCD
对于每个数,我们可以将它替换成
令
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=100005;
int n;
int a[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
int v=*min_element(a+1,a+n+1);
bool f1=true,f2=true;
for(int i=1;i<=n;i++)
{
if(a[i]%v!=0) f1=false;
if(a[i]!=v&&(a[i]-1)/2<v) f2=false;
}
if(f1||f2) cout<<v;
else cout<<v/2;
return 0;
}
L. Permutation Compression
可以发现,最优策略肯定是从大到小删,线段树上二分找每个数左边和右边第一个比他大的数,将所有 std::multiset
里,找到第一个比当前区间大的操作使用就可以了。操作完就把这个位置设成
#include<iostream>
#include<cstdio>
#include<set>
#include<algorithm>
using namespace std;
const int N=200005;
const int INF=1061109567;
int n,m,k;
int a[N],b[N];
int l[N];
int pos[N];
bool vis[N];
struct Segment_Tree
{
#define ls i*2
#define rs i*2+1
struct Node
{
int l,r;
int mx,sum;
}tree[N*4];
void push_up(int i)
{
tree[i].mx=max(tree[ls].mx,tree[rs].mx);
tree[i].sum=tree[ls].sum+tree[rs].sum;
return;
}
void build(int i,int l,int r)
{
tree[i].l=l,tree[i].r=r;
tree[i].mx=0;
if(l==r)
{
tree[i].mx=a[l];
tree[i].sum=1;
return;
}
int mid=(l+r)/2;
build(ls,l,mid);
build(rs,mid+1,r);
push_up(i);
return;
}
void modify(int i,int u,int v,int w)
{
if(tree[i].l==tree[i].r)
{
tree[i].mx=v;
tree[i].sum=w;
return;
}
if(u<=tree[ls].r) modify(ls,u,v,w);
else modify(rs,u,v,w);
push_up(i);
return;
}
int querypre(int i,int u,int v)
{
if(tree[i].mx<=v) return 0;
if(tree[i].l==tree[i].r) return tree[i].l;
if(u<=tree[ls].r) return querypre(ls,u,v);
else
{
if(tree[rs].mx<=v) return querypre(ls,u,v);
int lst=querypre(rs,u,v);
if(lst!=0) return lst;
else return querypre(ls,u,v);
}
}
int querysuf(int i,int u,int v)
{
if(tree[i].mx<=v) return n+1;
if(tree[i].l==tree[i].r) return tree[i].l;
if(u>=tree[rs].l) return querysuf(rs,u,v);
else
{
if(tree[ls].mx<=v) return querysuf(rs,u,v);
int lst=querysuf(ls,u,v);
if(lst!=n+1) return lst;
else return querysuf(rs,u,v);
}
}
int query(int i,int l,int r)
{
if(l<=tree[i].l&&tree[i].r<=r) return tree[i].sum;
int res=0;
if(l<=tree[ls].r) res+=query(ls,l,r);
if(r>=tree[rs].l) res+=query(rs,l,r);
return res;
}
#undef ls
#undef rs
}T;
void solve()
{
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=m;i++)
cin>>b[i];
for(int i=1;i<=k;i++)
cin>>l[i];
for(int i=1;i<=n;i++)
pos[a[i]]=i,vis[i]=false;
for(int i=1;i<=m;i++)
vis[b[i]]=true;
for(int i=1;i<=m;i++)
if(pos[b[i]]<pos[b[i-1]])
{
cout<<"NO\n";
return;
}
multiset<int,greater<int>>s;
for(int i=1;i<=k;i++)
s.insert(l[i]);
T.build(1,1,n);
for(int i=1;i<=n;i++)
if(vis[a[i]]) T.modify(1,i,a[i],1);
for(int i=n;i>=1;i--)
if(!vis[i])
{
int p=pos[i];
int l=T.querypre(1,p,i),r=T.querysuf(1,p,i);
int sum=T.query(1,l+1,r-1);
auto it=s.lower_bound(sum);
if(it==s.end())
{
cout<<"NO\n";
return;
}
s.erase(it);
T.modify(1,p,-INF,0);
}
cout<<"YES\n";
return;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
int T;
cin>>T;
while(T--)
solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)