2025-10-25 MX-S 模拟赛 赛后总结【MX】
赛时 Record
没有大洋里,没有文件读写,没有表格Markdown
这是三无比赛吗
- 8:00 开 T1。
 - 8:23 过了小样里。但是为何 T1 就出 dp。
 - 8:28 看不出来 T2 是啥。再 think 一会。
 - 8:33 发了大洋里。T1 的神秘 dp 过了大洋里。
 - 8:45 好像看出来了,又好像没看出来。
 - 9:24 这个贪心真是真的吗。。。
 - 9:38 为何大洋里能过,这贪心真对吗,好像对的吧。。
 - 9:51 为何 T3 找规律。
 - 10:05 T3 其实存在一个非常简单的两行代码的 \(O(n)\) 50pts 做法。
 - 10:10 欸我草想到了根号分治做法。感觉非常真啊。
 - 10:30 我草前 10000 个答案全对了我草。
 - 10:33 结束比赛。
 
结果是 100+100+100+0+0。
我草我战胜 T3 了!!!!
T1 放杆子
题意
数轴上有 \(n\) 个杆子,杆子竖立的时候占用位置 \(p_i\),向左放倒时占用位置 \([p_i-h_i,p_i]\),向右放倒时占用位置 \([p_i,p_i+h_i]\)。
杆子之间占用的位置不能重叠,问你最多可以放倒多少根杆子。
赛时
一眼顶针,鉴定为 dp。
题解
能贪。但是我糖了。
设计 dp 状态 \(dp_{i,0/1/2}\) 分别为第 \(i\) 根杆子竖立、向左倒、向右倒时,前 \(i\) 根杆子最多可以放倒的数量。
转移很显然,可以自己看代码理解。
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define infll 0x3f3f3f3f3f3f3f3fll
using namespace std;
int n;
struct node{
    long long x,h;
    bool operator<(const node&_Q)const{return x<_Q.x;}
}a[200010];
int dp[200010][3]; // 0-none 1-left 2-right
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i].x>>a[i].h;
    sort(a+1,a+1+n);
    a[0].x=-inf;
    a[0].h=-inf;
    for(int i=1;i<=n;i++){
        dp[i][0]=max(dp[i-1][0],dp[i-1][1]);
        if(a[i].x-a[i-1].x>a[i-1].h) dp[i][0]=max(dp[i][0],dp[i-1][2]);
        if(a[i].x-a[i-1].x>a[i].h) dp[i][1]=max(dp[i-1][0]+1,dp[i-1][1]+1);
        if(a[i].x-a[i-1].x>a[i].h+a[i-1].h) dp[i][1]=max(dp[i][1],dp[i-1][2]+1);
        dp[i][2]=max(dp[i-1][0]+1,dp[i-1][1]+1);
        if(a[i].x-a[i-1].x>a[i-1].h) dp[i][2]=max(dp[i][2],dp[i-1][2]+1);
    }
    int ans=0;
    for(int i=0;i<=2;i++) ans=max(ans,dp[n][i]);
    cout<<ans;
    return 0;
}
T2 二分图最小权完美匹配
题意
给你一个完全二分图,两侧各 \(n+1\) 个点,左侧点点权为 \(a_i\),右侧点点权为 \(b_i\)。对于左侧 \(i\) 到右侧 \(j\) 的边,边权为 \(\max(0,b_j-a_i)\)。
特殊的,\(a_{n+1}=+\infin\)。
对于一个完美匹配,其权值为所有匹配边的边权 \(\max\)。
求对于每个 \(i\),钦定 \(a_{n+1}\) 匹配到 \(b_i\) 点的情况下,最小化完美匹配的权值。
赛时
想了贪心,但是一直在想正确性所以卡了半天。
最后严肃决定试一下。结果过了。
题解
由于 \(a_{n+1}=+\infin\),所以和这个点匹配的点的边权都会变成 \(0\)。
所以很显然可以按点权顺序排序,然后一个一个找 \(\max\) 就行了。
建议离线下来做。
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define infll 0x3f3f3f3f3f3f3f3fll
using namespace std;
int n;
int a[200010];
struct node{
    int x,id;
    bool operator<(const node&_Q)const{return x<_Q.x;}
}b[200010];
multiset<int> s;
int ans[200010];
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>n;
    for(int i=1;i<=n+1;i++) cin>>b[i].x,b[i].id=i;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+1+n);
    sort(b+1,b+1+n+1);
    for(int i=1;i<=n;i++) s.insert(max(b[i+1].x-a[i],0));
    s.insert(0);
    ans[b[1].id]=(*s.rbegin());
    int nowmx=0;
    for(int i=2;i<=n+1;i++){
        s.erase(s.find(max(b[i].x-a[i-1],0)));
        nowmx=max(nowmx,max(b[i-1].x-a[i-1],0));
        ans[b[i].id]=max(nowmx,(*s.rbegin()));
    }
    for(int i=1;i<=n+1;i++) cout<<ans[i]<<" ";
    return 0;
}
T3 快速筛因子算法
题意
给定 \(n\),求 \(1\) 到 \(n\) 间每个数的所有因子的异或和的异或和。
赛时
首先观察到存在非常简单的 \(O(n)\) 50pts 做法。(其实是 55pts)
然后考虑在这个基础上优化,不难注意到,枚举到后面的因数的时候,\(\lfloor\frac{n}{x}\rfloor\) 有很多数都相等。
所以不难想到根号分治:对于 \(x\le \sqrt n\),枚举因子;对于 \(x\gt \sqrt n\),枚举 \(\lfloor \frac{n}{x}\rfloor\)。
然后就统计答案就可以了。
整除分块也能做,但是会被卡成 95pts(笑)。而且根号分治跑的比整除分块快三倍。
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define infll 0x3f3f3f3f3f3f3f3fll
using namespace std;
long long calc(long long n){
    long long ans=0;
    for(long long i=1;i<=n;i++) if((n/i)&1) ans^=i;
    return ans;
}
long long prexor(long long n){
	if(n==2) return 3;
	if(n&1) return ((n+1)>>1)&1;
	else return n+((n>>1)&1);
}
void solve(long long n){
    long long ans=0;
    long long nowfactor=1;
    for(;nowfactor<=n;nowfactor++){
        if((n/nowfactor)&1) ans^=nowfactor;
        if(nowfactor>sqrt(n)&&(n/nowfactor!=n/(nowfactor+1))) break; 
    }
    nowfactor++;
    long long maxdiv=n/nowfactor;
    for(long long nowdiv=1;nowdiv<=maxdiv;nowdiv+=2){
        long long minfac=(n/(nowdiv+1))+1;
        long long maxfac=(n/nowdiv);
        ans^=prexor(maxfac)^prexor(minfac-1);
    }
    cout<<ans<<"\n";
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    long long n;cin>>n;
    solve(n);
    return 0;
}
总结
在 T2 的正确性上纠结了半天,但结果正确性很显然。
一直说要严肃学习根号分治一直没时间,结果今天 T3 就是一个非常好的练习题。感谢出题 / 组题人。
                    
                
                
            
        
浙公网安备 33010602011771号