题解 | 小苯的前缀gcd构造

小苯的前缀gcd构造

https://www.nowcoder.com/practice/da0e37ccface4fc6a9380c9a8eac1fae

看到没有人想过dfs的解答,来一个相对比较好理解的dfs版本。

注意到n和m数据范围很小(50及以内),组数不超过10组,剪枝一下可以卡过时间。

注意到f(i)这个序列是不增序列,并且有 f(i+1) | f(i). 我们的目标是通过dfs搜索每一个位置的数。

怎么用dfs搜索构造序列呢?首先先预处理50以内的所有数字的因子,打表记录一下并降序排序所有的因子,在搜索开始前初始化一下因子表。接下来我们用pos表示当前枚举的位置,prev表示上一个元素的数值,sum表示当前已经选择的元素之和。显然,我们的x不能小于n(如果x=n,直接构造n个1)也不能大于n*m(如果x=n*m,直接构造n个m),如果x不满足那就不用构造,直接输出-1不可行。

接下来,我们dfs判断是否存在可行的构造。我们剩下n-pos个数字可以填充,如果是最小的情况,后面的所有数字都会是1,如果是最大的情况,当pos=0,所有的数字可以都是m,当pos不为0,所有的数字都是prev。我们先剪枝判断x在不在 [最小情况, 最大情况] 的区间中。

我们用curr表示当前的元素。首先,由于 f(i) 具有的性质,我们枚举curr是从prev的因子中从大到小枚举的。接下来就是剪枝,不难想对于后续的序列构造,我们有下界(后续元素全部都是1)和上界(后续元素全部都是curr) sum+curr+(rem−1)≤x≤sum+curr+(rem−1)×curr 解得:下界=⌈(x−sum)/rem⌉, 上界=x−sum−(rem−1)且 curr 必须满足 下界≤curr≤上界。若 下界 > 上界 我们同样剪枝;否则枚举 curr 时只会在这个区间枚举。代码如下

// Lang: cpp
// Auth: Hanzhi

#include<bits/stdc++.h>

using namespace std;

#define ll long long
#define ull unsigned long long
#define lll __int128
#define endl '\n'
#define pll pair<long, long>
#define pii pair<int, int>
#define pb push_back
#define fst first
#define scd second
#define hajimi ios::sync_with_stdio(false),
#define nanbei cin.tie(nullptr),
#define lvdou cout.tie(nullptr);

int n,m,x;
vector<int> res;
vector<int> fac[51];

void init()
{
    for(int i=1;i<=50;i++)
    {
        for(int j=1;j<=i;j++)
        {
            if(i%j==0) fac[i].push_back(j);
        }
        sort(fac[i].rbegin(),fac[i].rend());
    }
}

bool dfs(int pos, int prev, int sum)
{
    int remind=n-pos;
    if(remind==0) return sum==x;
    int mnposs=sum+remind;
    int mxposs=sum+(pos==0?remind*m:remind*prev);
    if(x<mnposs||x>mxposs) return false;
    int l=(x-sum+remind-1)/remind;
    int h=x-sum-(remind-1);
    if(l>h) return false;
    if(pos==0)
    {
        int st=min(m,h);
        for(int cur=st;cur>=l;cur--)
        {
            res.push_back(cur);
            if(dfs(pos+1, cur, cur+sum)) return true;
            res.pop_back();
        }
    }
    else {
        for(auto cur:fac[prev])
        {
            if(cur<l) break;
            if(cur>h) continue;
            res.push_back(cur);
            if(dfs(pos+1, cur, sum+cur)) return true;
            res.pop_back();
        }
    }
    return false;
}

void solve(){
    cin>>n>>m>>x;
    if(x<n||x>n*m)
    {
        cout<<-1<<endl;
        return ;
    }
    res.clear();
    if(dfs(0, 0, 0))
    {
        for(auto i:res) cout<<i<<" ";
        cout<<endl;
    }
    else cout<<-1<<endl;
    return ;
}

int main(){
    hajimi nanbei lvdou
    int T=1;
    cin>>T;
    init();
    while(T--) solve();
    return 0;
}

全部评论

相关推荐

不愿透露姓名的神秘牛友
05-20 16:14
已编辑
不止遇到一次了,什么都不会,让提合并请求,问什么是合并请求。让gitlab.页面把测试截图附上,不知道截图要放在哪,那么大的编辑看不到吗让配开发机,问ip是什么东西……这都咋进来的啊,我们(我2023年毕业)那会儿没AI的时候面试都是直接linux,docker,k8s,git,结构与算法,计网。怎么才过去2年,实习生跟傻子一样,有些问题问的我难受,不会git&nbsp;commit,不会git&nbsp;pull,不会切换分支,直接要覆盖master....————而且态度非常敷衍,3天前给开个仓库权限,连本地都没有拉下来。让写一个小文档,都是说一句,写一句,说把目录加上,挺嗤之以鼻,最后还是把目录加上了😂😂任何文档和注释都是方便后来人的,现在的人真的很自负啊,打开github看看任何一个开源项目的文档和注释,都写的很详细。难道现在的同学在校期间不经常拉开源项目看源码学习吗?&nbsp;哪怕是一个swap函数,开源项目里都经常注释:1&nbsp;3&nbsp;5&nbsp;7&nbsp;9&nbsp;2&nbsp;4&nbsp;6&nbsp;8&nbsp;10^&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;^l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rswap:{功能描述}{使用样例}————给我气笑了,没次问我有什么任务的时候,我都是说,优先你学校导师的项目,然后再做公司需求。然后给了两个需求,一个月内搞定就行,既然是agent开发,1.&nbsp;部署需要维护项目的开发环境2.阅读opencode/openclaude代码(我个人感觉龙虾的源码agent部分很常规,就一个channel+agent,还不如看claude泄露的代码和opencode)然后任务1搞了几周说因为环境问题,他申请到的远程开发机是linux,装的python2,项目是py3的,所以没搭建,我说你不行就用conda或docker把环境屏蔽了呢,没搭理我。任务2:看了很长时间代码,给我回了一句,opencode和openclaude是用go写的……我说你打开github看右下角那的语言是ts还是go……&nbsp;结果满脸懵的说ts是什么……我让看agent&nbsp;loop,哪怕全局搜索一下while(true),跳过去从头看到尾就大致清楚了,压根没看。————嘻嘻,我已经开始做社招简历了。
redf1sh:默认会git结果发现真不会,这种一看就是没做过项目的,真做过项目的至少会提交
点赞 评论 收藏
分享
评论
3
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务