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 就是一个非常好的练习题。感谢出题 / 组题人。

posted @ 2025-10-25 11:36  AeeE5x  阅读(29)  评论(0)    收藏  举报