回转寿司

题目描述

这里写图片描述

分块

你考虑有一堆人,价格为x的进去了出来会变成啥样。
那么肯定是找到这堆人所持价格的最大值y,如果x>y,出来的还是y,否则x会变成某个人手里的,然后出来的是y。
我们考虑分块,每个块维护一个数堆。
如果x要经过一个块,可以丢进数堆,再取出一个最大值。然后还要给这个块打上一个标记。
但是对于零散的不是很好做,即重构块,我们如何快速得到每个位置经过一系列标记后的值?
注意这个问题具有高度对称性,即一盘寿司一盘寿司的经过人,可以看做一个一个人走过寿司。
对标记也维护堆,然后枚举每个人,它手里的是x,那么把x丢进标记堆,再取出一个最小值,就是这个人更新后的。
堆要手打。
标记只在重构块时才丢进堆中,而且丢进堆前先排序。
一个块如果没有标记可以不重构。
一个x经过一个块如果还是x那么不给这个块打标记。
加上上述优化来卡常。

#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=400000+10,maxq=25000+10,B=633;
//priority_queue<int> tt[B+10],num[B+10];//num big tt small
int tt[B+10][maxq],num[B+10][B+10],zt[B+10],zn[B+10];
int bj[B+10][maxq],zb[B+10];
int a[maxn],belong[maxn];
int i,j,k,l,r,x,y,t,n,m,tot;
int read(){
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9'){
        if (ch=='-') f=-1;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
void push1(int x,int v){
    tot=zn[x];
    num[x][++tot]=v;
    int k=tot;
    while (k>1){
        if (num[x][k]>num[x][k/2]) swap(num[x][k],num[x][k/2]);
        else break;
        k/=2;
    }
    zn[x]=tot;
}
int pop1(int x){
    int t=num[x][1];
    tot=zn[x];
    num[x][1]=num[x][tot];
    tot--;
    int k=1,j;
    while (k*2<=tot){
        if (k*2+1>tot||num[x][k*2]>num[x][k*2+1]) j=k*2;else j=k*2+1;
        if (num[x][k]<num[x][j]) swap(num[x][k],num[x][j]);
        else break;
        k=j;
    }
    zn[x]=tot;
    return t;
}
void push2(int x,int v){
    tot=zt[x];
    tt[x][++tot]=v;
    int k=tot;
    while (k>1){
        if (tt[x][k]<tt[x][k/2]) swap(tt[x][k],tt[x][k/2]);
        else break;
        k/=2;
    }
    zt[x]=tot;
}
int pop2(int x){
    int t=tt[x][1];
    tot=zt[x];
    tt[x][1]=tt[x][tot];
    tot--;
    int k=1,j;
    while (k*2<=tot){
        if (k*2+1>tot||tt[x][k*2]<tt[x][k*2+1]) j=k*2;else j=k*2+1;
        if (tt[x][k]>tt[x][j]) swap(tt[x][k],tt[x][j]);
        else break;
        k=j;
    }
    zt[x]=tot;
    return t;
}
void rebuild(int x){
    if (zb[x]==0){
        zt[x]=zn[x]=0;
        return;
    }
    int i,t;
    sort(bj[x]+1,bj[x]+zb[x]+1);
    fo(i,1,zb[x]) push2(x,bj[x][i]);
    zb[x]=0;
    fo(i,(x-1)*B+1,min(x*B,n)){
        push2(x,a[i]);
        //tt[x].push(-a[i]);
        a[i]=pop2(x);
        /*a[i]=-tt[x].top();
        tt[x].pop();*/
    }
    zt[x]=zn[x]=0;
    /*while (!tt[x].empty()) tt[x].pop();
    while (!num[x].empty()) num[x].pop();*/
}
int main(){
    freopen("sushi.in","r",stdin);freopen("sushi.out","w",stdout);
    n=read();m=read();
    fo(i,1,n){
        a[i]=read();
        belong[i]=(i-1)/B+1;
        push1(belong[i],a[i]);
        //num[belong[i]].push(a[i]);
    }
    while (m--){
        j=read();k=read();x=read();
        l=belong[j];r=belong[k];
        if (l==r&&j<=k){
            rebuild(l);
            //if (j<k){
                fo(i,j,k)
                    if (x<a[i]) swap(x,a[i]);
            //}
            /*else{
                fo(i,j,min(l*B,n))
                    if (x<a[i]) swap(x,a[i]);
                fo(i,(l-1)*B+1,k)
                    if (x<a[i]) swap(x,a[i]);
            }*/
            fo(i,(l-1)*B+1,min(l*B,n)) {
                push1(l,a[i]);
                //num[l].push(a[i]);
            }
            printf("%d\n",x);
            continue;
        }
        rebuild(l);
        fo(i,j,min(l*B,n)) 
            if (x<a[i]) swap(x,a[i]);
        fo(i,(l-1)*B+1,min(l*B,n)){
            push1(l,a[i]);
            //num[l].push(a[i]);
        }
        l=l%belong[n]+1;
        while (l!=r){
            push1(l,x);
            //num[l].push(x);
            y=pop1(l);
            /*x=num[l].top();
            num[l].pop();*/
            if (y!=x){
                bj[l][++zb[l]]=x;
                //push2(l,x);
                //tt[l].push(-x);
                x=y;
            }
            l=l%belong[n]+1;
        }
        rebuild(r);
        fo(i,(r-1)*B+1,k)
            if (x<a[i]) swap(x,a[i]);
        fo(i,(r-1)*B+1,min(r*B,n)){
            push1(r,a[i]);
            //num[r].push(a[i]);
        }
        printf("%d\n",x);
    }
}
### GoC 编程语言与回转寿司算法 GoC 是一种基于 C 的扩展编程语言,它提供了更高效的内存管理和并发支持。对于回转寿司相关的算法问题,可以将其视为一个经典的分配问题,其中涉及排序、贪心策略以及双指针的应用。 以下是针对该问题的一个解决方案: #### 问题描述 给定 `n` 种寿司和 `m` 个人,每个人的胃口为 `b[i]`,每种寿司的数量为 `a[i]`。目标是按照一定的顺序分配寿司,使得每个人都能获得尽可能多的满意寿司。 --- #### 解决方案 可以通过以下步骤实现这一目标: 1. **输入处理**:读取寿司数量数组 `a[]` 和人的胃口数组 `b[]`。 2. **排序**:将胃口数组按降序排列,以便优先满足需求较大的人[^1]。 3. **分配逻辑**:利用双指针方法逐一匹配寿司和人,并记录结果。 4. **输出结果**:打印每个人最终能获取到的寿司编号。 下面是使用 GoC 实现的具体代码示例: ```goc #include <stdio.h> #include <stdlib.h> typedef struct { int appetite; int index; } Person; // 比较函数用于排序 int compare(const void *p1, const void *p2) { return ((Person *)p2)->appetite - ((Person *)p1)->appetite; } void assignSushi(int n, int m, int a[], Person b[]) { // 对胃口数组进行排序 qsort(b, m, sizeof(Person), compare); // 初始化结果数组 int result[m]; for (int i = 0; i < m; i++) { result[b[i].index] = -1; } // 使用双指针分配寿司 int j = 0; for (int i = 0; i < n && j < m; i++) { while (j < m && b[j].appetite >= a[i]) { result[b[j].index] = i + 1; // 寿司编号从1开始 j++; } } // 输出结果 for (int i = 0; i < m; i++) { printf("%d\n", result[i]); } } int main() { int n, m; scanf("%d %d", &n, &m); int a[n]; for (int i = 0; i < n; i++) { scanf("%d", &a[i]); } Person b[m]; for (int i = 0; i < m; i++) { scanf("%d", &b[i].appetite); b[i].index = i; } assignSushi(n, m, a, b); return 0; } ``` --- #### 关键点解析 1. **排序的重要性** 将人的胃口按降序排列能够确保每次分配都最大化当前剩余资源的价值[^1]。 2. **双指针优化** 利用两个指针分别遍历寿司和人,减少不必要的重复计算,从而提高效率[^2]。 3. **边界条件处理** 当某个人无法被满足时,默认返回 `-1` 表示无可用寿司[^3]。 --- ### 性能分析 此算法的时间复杂度主要由两部分组成: - 排序操作:\( O(m \log m) \)[^1] - 分配过程:\( O(n + m) \) 总体时间复杂度为 \( O(m \log m + n) \),适用于大多数实际场景中的数据规模。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值