2025春季杭电多校3题解
翻车了
1005
没什么好说的,并查集维护就行
void solve(){
int n;
cin>>n;
map<int,bool>vis;
vector<int>a(n+1);
for(int i=1;i<=n;i++){
cin>>a[i];
vis[i]=true;
}
vector<int>fa(n+1);
iota(fa.begin(),fa.end(),0);
auto find=[&](int x)->int{
while(x!=fa[x]){
x=fa[x]=fa[fa[x]];
}
return x;
};
auto merge=[&](int x,int y)->void{
x=find(x),y=find(y);
if(x!=y){
fa[x]=y;
}
};
for(int i=1;i<=n;i++){
int x=i-a[i],y=i+a[i];
if(vis[x])
merge(x,i);
if(vis[y])
merge(y,i);
}
vector<int>ans;
for(int i=1;i<=n;i++){
if(find(i)==i){
ans.push_back(i);
}
}
cout<<ans.size()-1<<endl;
}
1010
假设配送站的位置为\((a,b)\),那么以\((a,b)\)为原点作坐标系,客户的位置\((x,y)\)在每个象限的情况都考虑下,推出每种情况曼哈顿距离的表达式(去掉绝对值)。发现只用维护全局\(max(x+y),max(x-y),max(y-x),min(x+y)\)。这个维护输入的时候就能预处理出来。然后枚举所有的配送站位置,对每一个配送站位置计算四个象限的曼哈顿距离,求出最大值,再用最大值更新最后的答案(要求最大值最小,就是取所有最大值中的最小值)。详细见代码:
void solve(){
int n,m;
cin>>n>>m;
int s1=-INF,s2=INF,s3=-INF,s4=-INF;
for(int i=1;i<=n;i++){
int x,y;
cin>>x>>y;
s1=max(s1,x+y);
s2=min(s2,x+y);
s3=max(s3,x-y);
s4=max(s4,y-x);
}
vector<int>a(m+1),b(m+1);
for(int i=1;i<=m;i++){
cin>>a[i]>>b[i];
}
int ans=INF;
for(int i=1;i<=m;i++){
int r1=s1-(a[i]+b[i]);
int r2=a[i]+b[i]-s2;
int r3=b[i]-a[i]+s3;
int r4=a[i]-b[i]+s4;
int tep=max({r1,r2,r3,r4});
ans=min(ans,tep);
}
cout<<ans<<endl;
}
1009
这个题是atcode中的原,abc395的D题。我们考虑维护三个信息\(a[i]\)表示人所在的位置,\(b[i]\)表示部落所在的位置,\(c[i]\)表示位置\(i\)上的部落的编号。对于操作2,相当于把人x所在的位置改成部落y的位置;对于操作3,相当于交换壳子,即我们不交换部落中具体的人。假设部落1所在的位置为\(ip1\),部落2所在的位置为\(ip2\),那么就有\(c[ip1]\)=部落1,\(c[ip2]\)=部落2,我们交换部落这个壳子,让\(c[ip1]\)=部落2,\(c[ip2]\)=部落1,那么原本在\(ip1\)位置上的所有人所在的部落就改成了部落2,实现了交换;对于操作4,查询人在的部落,就是查询人在的位置上的部落编号。
以上思路是\(abc395\)的解法,这道题中多了一个操作1:a 部落与 b部落结盟。结盟操作使部落合并,新部落的编号是a。两个部落结盟,那么两个部落肯定共享一个位置,直接用并查集维护,实现共享位置;新部落的编号是a,那我就找部落所在位置的根节点,然后把这个位置上的部落编号改成a就行了。查询的时候查人在的位置上的部落编号,人的位置须是根节点的位置。有点乱了,详细见代码。
struct DSU{
vector<int>fa,siz;
DSU(int _n):fa(_n+1,0),siz(_n+1,1){
iota(fa.begin(),fa.end(),0);
}
int find(int x){
while(x!=fa[x])
x=fa[x]=fa[fa[x]];
return x;
}
void merge(int x,int y){
x=find(x),y=find(y);
if(x!=y){
fa[x]=y;
siz[y]+=siz[x];
}
}
};
void solve(){
int n,q;
cin>>n>>q;
vector<int>a(n+1);//维护人所在的位置
vector<int>b(n+1);//维护部落所在的位置
vector<int>c(n+1);//维护位置上的部落编号
for(int i=1;i<=n;i++){
a[i]=b[i]=c[i]=i;
}
DSU dsu(n+1);
while(q--){
int opt;
cin>>opt;
if(opt==1){
int x,y;
cin>>x>>y;
dsu.merge(b[x],b[y]);
int r=dsu.find(b[x]);
c[r]=x;
b[x]=b[y]=r;
}else if(opt==2){
int x,y;
cin>>x>>y;
a[x]=b[y];
}else if(opt==3){
int x,y;
cin>>x>>y;
int ip1=b[x],ip2=b[y];
c[ip1]=y,c[ip2]=x;
swap(b[x],b[y]);
}else{
int x;
cin>>x;
cout<<c[dsu.find(a[x])]<<endl;
}
}
}
1003
我要补一下优先队列了,不然迟早被创死。
初始时,针对每个能力维度建立小根堆,按该维度的要求值升序排列所有公司,确保优先处理最低门槛的面试机会。每次循环遍历所有维度,从堆顶依次取出当前能力可满足的公司,并累计其已通过的维度数;当某公司所有维度均达标时,立即将其加入处理队列,同步提升各维度能力值,触发新一轮的解锁检查——此时其他公司可能因能力提升而满足新的维度要求。此过程通过多轮迭代不断“解锁”可达标的公司,直至某轮循环中无新增公司可处理为止,最终通过已处理公司总数是否等于总数量判断可行性。该策略通过贪心选择最小要求的公司优先处理,并实时更新能力状态,确保了最优的解锁顺序和全局正确性。
using T2=tuple<int,int>;
using pq=priority_queue<T2,vector<T2>,greater<>>;
void solve(){
int n,m;
cin>>n>>m;
vector<int>a(m+1);
for(int i=1;i<=m;i++){
cin>>a[i];
}
vector c(n+1,vector<int>(m+1));
vector w(n+1,vector<int>(m+1));
vector<pq>q(m+1);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>c[i][j];
q[j].emplace(c[i][j],i);
}
for(int j=1;j<=m;j++){
cin>>w[i][j];
}
}
vector<int>cnt(n+1,0);
int ans=0;
while(true){
bool flag=false;
for(int j=1;j<=m;j++){
while(!q[j].empty()){
auto[x,y]=q[j].top();
if(x>a[j]){
break;
}
flag=true;
q[j].pop();
cnt[y]++;
if(cnt[y]==m){
for(int k=1;k<=m;k++){
a[k]+=w[y][k];
}
ans++;
}
}
}
if(!flag) break;
}
if(ans==n){
cout<<"YES"<<endl;
}else{
cout<<"NO"<<endl;
}
}
1007
可持久化trie的纯板子题,那个公式等价于\(a_{i}异或x\)。然后可持久化就行。学可持久化trie的第一道例题就是这个QwQ
const int N = 2e5+10;
int trie[N * 33][2], rt[N], id[N*33], idx;
void insert(int num, int k) {
rt[k] = ++idx;
id[idx] = k;
int x = rt[k - 1], y = rt[k];
for (int i = 31; i >= 0; i--) {
int j = num >> i & 1;
trie[y][!j] = trie[x][!j];
trie[y][j] = ++idx;
id[idx] = k;
x = trie[x][j], y = trie[y][j];
}
}
int query(int l, int r, int num) {
int p = rt[r], ans = 0;
for (int i = 31; i >= 0; i--) {
int j = num >> i & 1;
if (trie[p][!j]) {
if (l <= id[trie[p][!j]] && id[trie[p][!j]] <= r) {
ans += 1 << i;
p = trie[p][!j];
} else {
p = trie[p][j];
}
} else {
p = trie[p][j];
}
}
return ans;
}
void solve() {
int n, q;
cin >> n >> q;
for (int i = 1; i <= n; i++) {
int x;
cin >> x;
insert(x, i);
}
while (q--) {
int l, r, num;
cin >> l >> r >> num;
cout << query(l, r, num) << endl;
}
memset(rt, 0, sizeof(rt));
memset(trie, 0, sizeof(trie));
idx = 0;
}

浙公网安备 33010602011771号