2022/7/17 每日一题(构造+数学+贪心+指针)

Posted 钟钟终

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2022/7/17 每日一题(构造+数学+贪心+指针)相关的知识,希望对你有一定的参考价值。

D. Permutation Restoration
题意:数组a(由1~n组成)通过计算格式i/a[i]转化为数组b,现在给定数组b,要求还原出数组a,输出其中一种可能即可。
思路:
1.i/a[i]=b[i]可通过数学思维转化为 a[i]*b[i]=<i<a[i]*(b[i]+1)
进一步转化为 i/(b[i]+1)<a[i]<=i/b[i],最终为 i/(b[i]+1)+1=<a[i]<=i/b[i]
2.由此确定了每一个a[i]的取值范围,下一步确定1~n中每一个值的归属。
3.对每个a[i]的范围进行排序,根据左范围l进行从小到大排序;若相等,则再根据右范围升序排列。
4.创建一个pair类型的优先队列,第一关键字为右范围,第二关键字为b[i]中编号。

(pair默认是先对第一个关键字从小到大排序,如果第一关键字相同,在对第二关键字从小到大排序,都是升序)
5.非常关键的特判,如果b[i]为0,那么a[i]范围应该是[i+1,n].要特别得区别于数学公式推出来的范围。

代码:

#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
#define pii pair<int,int>
using namespace std;
const int N=1e6+6;
struct node

    int l,r,id;
e[N];
int n,a[N],b[N];
bool cmp(node n1,node n2)

    if(n1.l==n2.l)
        return n1.r<n2.r;
    return n1.l<n2.l;

signed main()

    int t;cin>>t;
    while(t--)
    
        cin>>n;
        for(int i=1;i<=n;i++)
        
            cin>>b[i];
            e[i].id=i;
            e[i].l=i/(b[i]+1)+1;
            if(b[i]==0)
                e[i].r=n;
            else
                e[i].r=i/b[i];
        
        sort(e+1,e+n+1,cmp);
        priority_queue<pii,vector<pii>,greater<pii> >q;
        int k=1;
        for(int i=1;i<=n;i++)
        
            while(k<=n&&e[k].l<=i)
            
                q.push(e[k].r,e[k].id);
                k++;
            
            int g=q.top().second;
            q.pop();
            a[g]=i;
        
        for(int i=1;i<=n;i++)
            cout<<a[i]<<" ";
        cout<<endl;
    
    return 0;


以上是关于2022/7/17 每日一题(构造+数学+贪心+指针)的主要内容,如果未能解决你的问题,请参考以下文章

[ 9.28 ]CF每日一题系列—— 940A规律构造

2021暑假每日一题 week7 完结

变量类型构造器封装以及 LeetCode 每日一题

2021暑假每日一题 week5 完结

2021夏季每日一题 week6 完结

[每日一题]:P1016 旅行家的预算 -- 反悔贪心