Denso Create Programming Contest 2026(AtCoder Beginner Contest 443)vp补题

D 枚举

题意:每次操作对数组中数-1,相邻数 ∣ x − y ∣ ≤ 1 |x-y|\leq 1 ∣x−y∣≤1,即 R i ≤ R i + 1 + 1 , R i ≤ R i − 1 + 1 R_i\leq R_{i+1}+1, R_i\leq R_{i-1}+1 Ri≤Ri+1+1,Ri≤Ri−1+1

用小的数去把大的数往小拉

用 R i − 1 R_{i-1} Ri−1一侧的数限制后,由于不知道另一侧的情况,再用 R i + 1 R_{i+1} Ri+1限制后, R i + 1 R_{i+1} Ri+1又会被右边的数影响而改变

所以需要循环两次,从前和从后隔一次,来保证每个数被相邻的不会改变的数限制。

cpp 复制代码
void solve(){
  int n;cin>>n;
  vector<int>r(n+2);
  forr(i,1,n){
    cin>>r[i];
  }
  r[0]=r[2],r[n+1]=r[n-1];
  int ans=0,cnt=1,mn=r[1];
  forr(i,1,n){
    int now=r[i];
    if(r[i]>r[i-1]+1)now=min(now,r[i-1]+1);
    // if(r[i]>r[i+1]+1)now=min(now,r[i+1]+1);
    ans+=r[i]-now;
    r[i]=now;
  }
  reforr(i,1,n){
    int now=r[i];
    // if(r[i]>r[i-1]+1)now=min(now,r[i-1]+1);
    if(r[i]>r[i+1]+1)now=min(now,r[i+1]+1);
    ans+=r[i]-now;
    r[i]=now;
  }
  cout<<ans<<endl;
}

E 递归

题意:从第n行开始向上走,对第1行的每个点判断能否到达

  • 如果要走的地方是墙,满足该墙下面的行没有别的墙(直通 i ∼ n i\sim n i∼n行),可以破该墙

只是向上走,可以逐行递推可到达的位置

本行可到达的地方:

  • 空地
  • 下面直通的墙
    "直通"的状态也可以逐行递推,我的做法是 i i i本行更新完后给 i − 1 i-1 i−1行用
cpp 复制代码
void solve(){
  int n,c;cin>>n>>c;
  vector<string>s(n+1);
  vector<vint>vis(n+1,vector<int>(n+1,0));//能否到达
  vector<int>all(n+1,0);//"直通"状态
  forr(i,1,n){
    cin>>s[i];
    s[i]=' '+s[i];
  }
  vis[n][c]=1;
  forr(j,1,n)all[j]=(s[n][j]=='.');//初始化"直通状态" 初始位置破不了任何墙 只有空地满足"直通"
  auto notin=[&](int x){
    return x>n||x<1;
  };
  reforr(i,1,n-1){
    forr(j,1,n){
      //本行可到达的地方 找i+1行能否到达
      if(s[i][j]=='.'){//空地
        forr(k,-1,1){
          if(notin(j+k))continue;
          vis[i][j]|=vis[i+1][j+k];
        }
      }else{
        if(!all[j])continue;//破不了墙
        //可以破墙
        forr(k,-1,1){
          if(notin(j+k))continue;
          vis[i][j]|=vis[i+1][j+k];
        }
      }
		//递推"直通"状态
      if(s[i][j]=='#')all[j]&=vis[i][j];//如果本行是墙 必须同时满足这个墙直通+能到达(到不了这墙就破不了,更别提后面的了)
      //如果本行是空地 不影响状态
    }
  }
  // forr(i,1,n){forr(j,1,n)cout<<vis[i][j];cout<<endl;}
  forr(j,1,n)cout<<vis[1][j];cout<<endl;
}

F BFS 剪枝

参考@枫落 dalao题解 @StelaYuri dalao题解

题意:找到最小的"好整数"(各位数字非递减),使其是给定正整数N的倍数。不存在输出 -1。

(以下分析来自豆包)

核心思路

我们可以用**广度优先搜索(BFS)**来按"数字长度从小到大"的顺序生成所有可能的好整数,并在过程中记录余数,从而快速找到最小的解。

  1. 状态定义 :每个状态用 (余数 r, 最后一位数字 d) 表示,其中:
    • r r r 是当前数字模 N N N 的余数。
    • d d d 是当前数字的最后一位,保证下一位数字 k ≥ d k \ge d k≥d,从而满足"非递减"的条件。
  2. 剪枝策略 :使用 vis[r][d] 数组标记已经访问过的状态。如果同一个 (r, d) 再次出现,说明可以通过更短的数字得到相同的余数,因此无需再次入队,避免了无效搜索。
  3. 终止条件 :当某个状态的余数 r = 0 r = 0 r=0 且数字非空时,该数字即为所求的最小好整数。

时间复杂度分析

  • 状态总数 :余数 r r r 有 N N N 种可能,最后一位数字 d d d 有 9 种可能(1到9),因此总共有 O ( N × 9 ) O(N \times 9) O(N×9) 个状态。
  • 每个状态的操作 :每个状态出队后,会枚举从 d d d 到 9 的数字(最多9次),每次操作是 O ( 1 ) O(1) O(1) 的。
  • 总体复杂度 : O ( N × 9 × 9 ) = O ( N ) O(N \times 9 \times 9) = O(N) O(N×9×9)=O(N), ≈ 2.43 × 10 8 \approx 2.43 \times 10^8 ≈2.43×108,需要小心卡常

关键点

  • BFS保证最小性:按数字长度从小到大搜索,第一个找到的余数为0的解就是最小的。
  • 状态剪枝vis[r][d] 确保每个状态只访问一次,避免了指数级的时间爆炸。
cpp 复制代码
struct node
{
  int r,d;
  string res;
};
//没有用longlong 
int vis[N][10];
inline void solve(){
  int n;cin>>n;
  if(n<10)return cout<<n<<endl,void();//特判节省时间
  queue<node>q;
  q.push({0,1,""});
  while (q.size())
  {
    auto [r,d,s]=q.front();q.pop();
    if(r==0&&s!="")
      return cout<<s<<endl,void();
    
    forr(i,d,9){//下一位>=d
      int nr=(r*10+i)%n;//nr和上一个数的r,d有关
      //一种(r,d)枚举过一次就可以 重复枚举得到的路径相同但是结果更大 不会更优 vis剪枝
      if(vis[nr][i])continue;
      vis[nr][i]=1;
      string ns=s+char(i+'0');
      q.push({nr,i,ns});
    }
  }
  cout<<-1<<endl;
}

G 类欧几里得

请你找出满足 0 ≤ k < N 0≤k<N 0≤k<N且 ( A k + B ) m o d    M > k (Ak+B)\mod M>k (Ak+B)modM>k的整数 k k k有多少个。

暴力必超时,关键在于化不等式

我服了手写的类欧几里得有四个点过不去,不知道怎么处理了,对类欧几里得理解还不深,之后慢慢找原因吧,红温了

错误例子:

1

2 3 1 0

cpp 复制代码
//int 已开longlong
// int floor_sum(int a,int b,int c,int n){//递归
//     int res=0;
//     if(a>=c){
//         res+=((n-1)*n/2)*(a/c);
//         a%=c;
//     }
//     if(b>=c){
//         res+=n*(b/c);
//         b%=c;
//     }
//     int m=(a*n+b)/c;
//     if(m==0)return res;
//     // res+=n*m-floor_sum(c,c-b-1,a,m);
//     res+=n*m-floor_sum(c,(a*n+b)%c,a,m);
//     return res;
// }
int floor_sum(int a,int b,int c,int n){//迭代
    int res=0;
    while(1){
        if(a>=c){
            res+=((n-1)*n/2)*(a/c);
            a%=c;
        }
        if(b>=c){
            res+=n*(b/c);
            b%=c;
        }
        int mx=(a*n+b);
        if(mx<c)break;
        n=mx/c,b=mx%c;
        swap(c,a);
        
    }
    return res;
}
void solve(){
    int n,m,a,b;cin>>n>>m>>a>>b;
    int ans;
    //是边界值的问题吗? a=-1能拿进去计算吗
    // if(a==0&&b==0)ans=1;
    // else if(a==0){
    //     int r=b%m;
    //     ans=min(n,r);
    // }
    // else if(b==0){
    //     if(a==1)ans=0;
    //     else 
    // }
    // else 
    ans=n-floor_sum(a,b,m,n)+floor_sum(a-1,b-1,m,n);
    cout<<ans<<endl;
}
相关推荐
寻寻觅觅☆9 小时前
东华OJ-基础题-106-大整数相加(C++)
开发语言·c++·算法
偷吃的耗子9 小时前
【CNN算法理解】:三、AlexNet 训练模块(附代码)
深度学习·算法·cnn
今天只学一颗糖9 小时前
1、《深入理解计算机系统》--计算机系统介绍
linux·笔记·学习·系统架构
testpassportcn10 小时前
AWS DOP-C02 認證完整解析|AWS DevOps Engineer Professional 考試
网络·学习·改行学it
化学在逃硬闯CS10 小时前
Leetcode1382. 将二叉搜索树变平衡
数据结构·算法
ceclar12310 小时前
C++使用format
开发语言·c++·算法
Gofarlic_OMS11 小时前
科学计算领域MATLAB许可证管理工具对比推荐
运维·开发语言·算法·matlab·自动化
夏鹏今天学习了吗11 小时前
【LeetCode热题100(100/100)】数据流的中位数
算法·leetcode·职场和发展
忙什么果12 小时前
上位机、下位机、FPGA、算法放在哪层合适?
算法·fpga开发
董董灿是个攻城狮12 小时前
AI 视觉连载4:YUV 的图像表示
算法