{题解}[jzoj4907]【NOIP2016提高组复赛】蚯蚓

传送门

Desription

图片

Analysis

65分想法:用维护一个最大值,暴力切割。
100分做法:
考虑一个有序序列a(当前蚯蚓长度)
每次必定是选择第一个,删除第一个,考虑把分裂出的插入序列,保证有序。
当切割一条蚯蚓 a1 时,设分成了 x1>y1
对于另一条蚯蚓 a2<a1 ,它所分成的 x2>y2 必定也满足 x2<x1,y2<y1
可以用链表进行删除和插入。
利用这一性质,可以维护两个指针,分别表示x,y必定小于的数字。
显然可见,指针只会扫一遍。
所以复杂度是 O(n)

Code

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn =  101000, maxm = 7070000, maxq = 220, maxnum = 100100100;
int n,m,q,u,v,t;
int head,tot;
int xx,yy;
struct node{
    int nex,las;
    int num;
}a[(maxm + maxn) * 2]; 
bool cmp(node a,node b)
{
    return a.num > b.num;
}
void inser(int x,int y)//把x插入到 y前一格
{
    tot ++;
    a[tot].num = x;
    a[tot].las = a[y].las,a[a[y].las].nex = tot;
    a[tot].nex = y,a[y].las = tot;
} 
void delet(int x)//把x格删除 
{
    a[a[x].las].nex = a[x].nex;
    a[a[x].nex].las = a[x].las;
    a[x].nex = a[x].las = -1;
} 
int main()
{
    freopen("earthworm.in","r",stdin);freopen("earthworm.out","w",stdout);
    //freopen("D:/LiuYuanHao/e.in","r",stdin);
    //freopen("D:/LiuYuanHao/e.out","w",stdout);
    scanf("%d%d%d%d%d%d", &n, &m, &q, &u, &v, &t);
    for (int i = 1;i <= n;i ++) 
    {
        int x;
        scanf("%d", &x);
        a[i].num = x;
    }
    sort(a + 1,a + 1 + n,cmp);

    head = 1;
    tot = n + 1;
    a[n + 1].num = -2147483647;
    a[1].nex = 2,a[n].las = n - 1,a[n].nex = n + 1,a[n + 1].las = n;
    for (int i = 2;i <= n - 1;i ++)
        a[i].las = i - 1,a[i].nex = i + 1;

    double p = (double)u / v;
    xx = 1, yy = 1;
    int tt = 0;
    for (int i = 1;i <= m;i ++)
    {
        int k;
        a[head].num += (i - 1) * q;
        if ((++ tt)%t==0) printf("%d ", a[head].num);
        int tmp2 = a[head].num * p, tmp1 = a[head].num - tmp2; //tmp1 >= tmp2
        k = xx;
            while (a[k].num + i * q> tmp1/*- (i) * q/* && k > 0*/) k = a[k].nex;
            inser(tmp1 - (i) * q,k); 
            xx = a[k].las;
        k = yy;
            while (a[k].num + i * q> tmp2/* - (i) * q/* && k > 0*/) k = a[k].nex;
            inser(tmp2 - (i) * q,k);
            yy = a[k].las;
        head = a[head].nex; 
        delet(a[head].las);
    }
    printf("\n");
    tt = 0;
    for (int  i = head;i != n + 1;i = a[i].nex) 
    {
        if ((++ tt)%t==0)
            printf("%d ", a[i].num + m * q);    
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值