NOIP2025模拟赛29

T1 T2 T3 T4
\(\color{#FFC116} 普及/提高-\) \(\color{#52C41A} 普及+/提高\) \(\color {#3498DB} 提高+/省选-\) \(\color{#9D3DCF} 省选/NOI-\)

参赛网址:https://oj.33dai.cn/d/TYOI/contest/68a830bac5d9c2f14c2aa5f9

本场契合当前竞赛国际导向“灵活应用,注重思维”,知识点都在提高组范围内,请认真打比赛,赛后好好补题。

T1 打怪【NOIP2025模拟赛T1】

题目传送门

题目难度:\(\color{#FFC116} 普及/提高-\)

算法标签:贪心,其他,二分查找,NOISG

思路

首先,我们发现,将一只怪物打死有两种方式:

  • 将一只怪物向左或向右移动到一个地雷然后引爆地雷

  • 减少一只怪物的生命值到 0

所以考虑对于第 \(i\) 只怪,\(\forall i \in [1,n]\),如果他移动到旁边地雷的距离都大于将它在原地打死的花费,那么就将它在原地打死。

否则就将它移到旁边的地雷即可。

::::warning[警告]{open}
优先使用靠右的地雷
::::

AC Code

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int maxn=2e5+5;
const int inf=1e18;
int n,k;
int ans;
struct node{
    int a,h;
    friend bool operator < (const node &x,const node &y){
        return x.a<y.a;
    }
}a[maxn];
int x[maxn];
int vis[maxn];

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>n>>k;
    for (int i=1;i<=n;i++)  cin>>a[i].a>>a[i].h;
    for (int i=1;i<=k;i++)  cin>>x[i];
    x[k+1]=-inf,x[k+2]=inf;
    k+=2;
    sort(x+1,x+k+1);
    sort(a+1,a+n+1);
    for (int i=1;i<=n;i++){
        int nxt=lower_bound(x+1,x+k+1,a[i].a)-x;
        if (x[nxt]==a[i].a){
            ans++;
            vis[nxt]=1;
        }
    }
    for (int i=1;i<=n;i++){
        int nxt=lower_bound(x+1,x+k+1,a[i].a)-x;
        if (x[nxt]==a[i].a) continue;
        int las=nxt-1;
        int f=a[i].a-x[las]+(vis[las]==0);
        int g=x[nxt]-a[i].a+(vis[nxt]==0);
        int l=a[i].h;
        if (min(f,g)>l)    ans+=l;
        else {
            if (f>=g){
                ans+=g;
                vis[nxt]=1;
            }
            else {
                ans+=f;
                vis[las]=1;
            }
        }
    }
    cout<<ans;
    return 0;
}

T2 弹珠游戏【NOIP2025模拟赛T2】

题目传送门

题目难度:\(\color{#52C41A} 普及+/提高\)

算法标签:贪心,动态规划,最大子段和

思路

题目要求的是:

无论 Bob 如何选择,都确保她 \(M\) 轮游戏不输。

那么我们就考虑最坏情况,所以 Bob 要最大化收益,则 Alice 猜奇数,Bob 就是用最大的偶数,如果没有偶数,就让 Alice 的收益最小。猜偶数的同理。

\(odd_i\) 是 Alice 猜奇数时,她的亏损(负数即为收益),\(even_i\) 同理。

  even[i]=omax;
  if (omax==0)    even[i]=-emin;
  odd[i]=emax;
  if (emax==0)    odd[i]=-omin;

Alice 为了不输,她肯定是亏损最小,取 \(\min(even_i,odd_i)\)

然后求 \(\min(even_i,odd_i)\) 的后缀最大子段和,如果 \(f_1 \ge m\),答案为 -1。

否则应该枚举每一位:如果可以用 Even 则直接输出 Even,否则考虑 Odd。

AC Code

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int maxn=3e5+5;
const int inf=1e18;
int T;
int n,m,k;
int f[maxn];
int a[maxn][5];
int even[maxn],odd[maxn];

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    // freopen("data_2.in","r",stdin);
    // freopen("data.out","w",stdout);
    cin>>T;
    while (T--){
        cin>>m>>n>>k;
        for (int i=1;i<=n;i++){
            int emin=inf,omin=inf;
            int emax=0,omax=0;
            for (int j=1;j<=k;j++){
                cin>>a[i][j];
                if ((a[i][j]&1)==0){
                    emin=min(emin,a[i][j]);
                    emax=max(emax,a[i][j]);
                }
                else{
                    omin=min(omin,a[i][j]);
                    omax=max(omax,a[i][j]);
                }
            }
            even[i]=omax;
            if (omax==0)    even[i]=-emin;
            odd[i]=emax;
            if (emax==0)    odd[i]=-omin;
        }
        f[n+1]=0;
        for (int i=n;i>=1;i--)  f[i]=max(f[i+1],0ll)+min(even[i],odd[i]);
        if (f[1]>=m) cout<<-1<<"\n";
        else {
            for (int i=1;i<=n;i++){
                if (f[i+1]+even[i]<m&&even[i]<m)  cout<<"Even ",m-=even[i];
                else    cout<<"Odd ",m-=odd[i];
            }
            cout<<"\n";
        }
    }
    return 0;
}

T3 兔子【NOIP2025模拟赛T3】

题目传送门

题目难度:\(\color {#3498DB} 提高+/省选-\)

算法标签:组合数学,差分,数据结构,树状数组,坐标旋转

思路

AC Code

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int maxn=5e5+5;
int n,m;
int x[maxn],y[maxn];
int nx[maxn],ny[maxn];
int tx[maxn],ty[maxn];
int bx[maxn],by[maxn];

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>n>>m;
    for (int i=1;i<=n;i++){
        cin>>x[i]>>y[i];
        nx[i]=bx[i]=x[i]+y[i];
        ny[i]=by[i]=x[i]-y[i];
    }
    sort(bx+1,bx+n+1);
    sort(by+1,by+n+1);
    for (int i=1;i<=n;i++){
        nx[i]=lower_bound(bx+1,bx+n+1,nx[i])-bx;
        ny[i]=lower_bound(by+1,by+n+1,ny[i])-by;
    }
    for (int i=1;i<=m;i++){
        int t;
        cin>>t;
        tx[1]-=2;
        tx[nx[t]]+=2;
        tx[nx[t]+1]+=2;
        tx[n+1]-=2;

        ty[1]-=2;
        ty[ny[t]]+=2;
        ty[ny[t]+1]+=2;
        ty[n+1]-=2;
    }
    for (int i=1;i<=n;i++)  tx[i]+=tx[i-1],ty[i]+=ty[i-1];
    for (int i=1;i<=n;i++){
        int ax=bx[nx[i]]+tx[nx[i]];
        int ay=by[ny[i]]+ty[ny[i]];
        cout<<(ax+ay)/2<<" "<<(ax-ay)/2<<"\n";
    }
    return 0;
}

T4 激光【NOIP2025模拟赛T4】

题目传送门

题目难度:\(\color{#9D3DCF} 省选/NOI-\)

算法标签:动态规划,线段树优化dp

思路

AC Code

posted @ 2025-10-01 12:44  Zzqyoung1121  阅读(8)  评论(0)    收藏  举报