蚯蚓

洛谷 P2827 蚯蚓

首先最容易想到的
85分 优先队列

#include <iostream>
#include <cstdio>
#include <queue>
#include <cmath>
using namespace std;
priority_queue<int> qy;
int main(){
	int n,m,t,q;
	double u,v,p;
	scanf("%d %d %d %lf %lf %d",&n,&m,&q,&u,&v,&t);
	p=u/v;
	for(int i=0;i<n;++i)
	{
		int d;
		scanf("%d",&d);
		qy.push(d);
	}
	int ans=0;
	for(int i=1;i<=m;++i)
	{
		int d=qy.top()+ans;//要先还原,不然计算d1 d2会出错 
		qy.pop();
		if(!(i%t))
			printf("%d ",d);
		int d1=floor(p*double(d)),d2=d-d1;
		d1-=ans;
		d2-=ans;
		d1-=q;
		d2-=q;
		//减掉加上的ans,由于d1 d2少加一次q,先减掉一次 
		//printf("%d %d %d\n",d,d1,d2);
		qy.push(d1);
		qy.push(d2);
		ans+=q;
	}
	printf("\n");
	for(int i=1;i<=n+m;++i)
	{
		int d=qy.top();
		if(!(i%t))
			printf("%d ",d+ans);
		qy.pop();
	}
	printf("\n");
	return 0;
}

看完题解…emmm
解释摘了aiyougege的题解

关键点:
发现此题中隐含的单调性.
发现先被切掉的蚯蚓分成的蚯蚓一定比后切掉的蚯蚓分成的蚯蚓大.

证明:
假设这两只蚯蚓分别为a,b,其中a>b.
那么它被切成a1,a2,t秒后, b被切成了b1,b2
此时a1,a2的长度为p*a+q*t,(1-p)*a+q*t
而b1,b2的长度却为p*(b+q*t), (1-p)*(b+q*t)
易看出a1>b1,a2>b2 .
也就是说根本不需要用一个堆来维护, 它本来就具有一定单调性.

那么就可以将这两堆依次存储, 加上还没被切过的蚯蚓.每次要切时在这三堆里面选择最大的, 切完再依次放回去.   所以这么做时间复杂度为O(m)O(m).再优化一下细节基本上就没问题了.

结论: 善于发现题目中隐含的单调性.

Tip:有些细节需要仔细考虑不然会很惨

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 7100005
int n,m,k,t;
double u,v,p;
struct T
{
    int h,t;
    int q[N];
}q[4];
bool cmp(int a,int b)
{
    return a>b;
}
void push(int d,int x)
{
    q[d].t++;
    q[d].q[q[d].t]=x;
    //printf("%d %d\n",q.t,q.q[q.t]);
}
void pop(int d)
{
    q[d].h++;
}
int max()
{
    int d1=1,d2;
    d2=q[2].q[q[2].h]>q[3].q[q[3].h]?2:3;
    if(q[1].h>q[1].t)//注意有可能q[1]为空 后面是0 而q[2] q[3] 会出现负数
        return d2;
    d1=q[1].q[q[1].h]>q[d2].q[q[d2].h]?d1:d2;
    return d1;
}
int main(){
    //freopen("a.txt","r",stdin);
    //freopen("b.txt","w",stdout);
    q[1].h=1,q[1].t=0;
    q[2].h=1,q[2].t=0;
    q[3].h=1,q[3].t=0;
    scanf("%d %d %d %lf %lf %d",&n,&m,&k,&u,&v,&t);
    p=u/v;
    for(int i=0;i<n;++i)
    {
        int l;
        scanf("%d",&l);
        push(1,l);
    }
    sort(q[1].q+1,q[1].q+n+1,cmp);
    int ans=0;
    for(int i=1;i<=m;++i)
    {
        int d=max();
        int x=q[d].q[q[d].h]+ans;
        if(!(i%t))
            printf("%d ",x);
        pop(d);
        int a=floor(double(x)*p),b=x-a;
        //printf("%d %d %d\n",x,a,b);
        a-=ans,b-=ans;
        a-=k,b-=k;
        if(a>b)
        {
            push(2,a);
            push(3,b);
        }
        else
        {
            push(2,b);
            push(3,a);
        }
        ans+=k;
    }
    printf("\n");
    for(int i=q[2].h;i<=q[2].t;++i)
    {
        push(1,q[2].q[i]);
    }
    for(int i=q[3].h;i<=q[3].t;++i)
    {
        push(1,q[3].q[i]);
    }
    sort(q[1].q+q[1].h,q[1].q+q[1].t+1,cmp);
    int y=0;
    for(int i=q[1].h;i<=q[1].t;++i)
    {
        y++;
        if(!(y%t))
            printf("%d ",q[1].q[i]+ans);
        pop(1);
    }
    return 0;
}

加优化
三个堆都具有单调性,每一次比较三个堆顶就能得到最大值

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 7100005
int n,m,k,t;
double u,v,p;
struct T
{
    int h,t;
    int q[N];
}q[4];
bool cmp(int a,int b)
{
    return a>b;
}
void push(int d,int x)
{
    q[d].t++;
    q[d].q[q[d].t]=x;
    //printf("%d %d\n",q.t,q.q[q.t]);
}
void pop(int d)
{
    q[d].h++;
}
int max()//三个都要判空 七种情况 无比麻烦...
{
    int d1,d2,d3;
    d1=q[2].q[q[2].h]>q[3].q[q[3].h]?2:3;
    d2=q[1].q[q[1].h]>q[3].q[q[3].h]?1:3;
    d3=q[2].q[q[2].h]>q[1].q[q[1].h]?2:1;
    if(q[1].h>q[1].t)
    {
        if(q[2].h>q[2].t)//1 2为空
            return 3;
        if(q[3].h>q[3].t)//1 3为空
            return 2;
        return d1;//1为空
    }
    if(q[2].h>q[2].t)
    {
        if(q[3].h>q[3].t)//2 3为空
            return 1;
        return d2;//2为空
    }
    if(q[1].h>q[1].t)//3为空
        return d3;
    return q[d1].q[q[d1].h]>q[d2].q[q[d2].h]?d1:d2;//都不为空 可以任意两个比较
}
int main(){
    //freopen("a.txt","r",stdin);
    //freopen("b.txt","w",stdout);
    q[1].h=1,q[1].t=0;
    q[2].h=1,q[2].t=0;
    q[3].h=1,q[3].t=0;
    scanf("%d %d %d %lf %lf %d",&n,&m,&k,&u,&v,&t);
    p=u/v;
    for(int i=0;i<n;++i)
    {
        int l;
        scanf("%d",&l);
        push(1,l);
    }
    sort(q[1].q+1,q[1].q+n+1,cmp);
    int ans=0;
    for(int i=1;i<=m;++i)
    {
        int d=max();
        int x=q[d].q[q[d].h]+ans;
        if(!(i%t))
            printf("%d ",x);
        pop(d);
        int a=floor(double(x)*p),b=x-a;
        //printf("%d %d %d\n",x,a,b);
        a-=ans,b-=ans;
        a-=k,b-=k;
        if(a>b)
        {
            push(2,a);
            push(3,b);
        }
        else
        {
            push(2,b);
            push(3,a);
        }
        ans+=k;
    }
    printf("\n");
    for(int i=1;i<=m+n;++i)//直接利用单调性 找三个队列最大值并出队
    {
        int d=max();
        int x=q[d].q[q[d].h]+ans;
        pop(d);
        if(!(i%t))
            printf("%d ",x);
    }
    return 0;
}
### 关于蚯蚓模拟的 C++ 实现 在讨论与蚯蚓相关的 C++ 模拟实现时,可以借鉴类似的模拟逻辑来设计程序。以下是基于题目描述和已知引用中的代码结构所构建的一个可能的解决方案。 #### 问题分析 假设我们需要模拟一条或多条蚯蚓的行为,比如它们如何移动、分裂或者与其他环境因素交互。这种类型的模拟通常涉及以下几个方面: 1. **状态表示**:每只蚯蚓的状态可以用若干变量表示,例如位置、长度或其他属性。 2. **行为定义**:定义蚯蚓的行为规则,例如移动方向、速度变化或分裂条件。 3. **输入处理**:读取初始数据并解析操作指令。 4. **输出结果**:按照指定格式打印最终的结果。 下面是一个简单的例子,展示如何通过 C++ 来实现一个基本的蚯蚓模拟器: ```cpp #include <iostream> #include <vector> using namespace std; int main() { int N, M; // N 表示蚯蚓数量,M 表示操作次数 cin >> N >> M; vector<int> worms(N); for (int i = 0; i < N; ++i) { cin >> worms[i]; // 输入每只蚯蚓的初始长度 } for (int step = 0; step < M; ++step) { char operation; cin >> operation; if (operation == 'S') { // 分裂操作 int index, split_ratio; cin >> index >> split_ratio; if (index >= 0 && index < worms.size()) { int length = worms[index]; int part1 = length * split_ratio / 100; int part2 = length - part1; worms.erase(worms.begin() + index); // 移除原蚯蚓 worms.insert(worms.begin() + index, {part1, part2}); // 插入两部分 } } else if (operation == 'G') { // 生长操作 int growth_value; cin >> growth_value; for (auto& worm : worms) { worm += growth_value; // 所有蚯蚓增长相同的值 } } } for (const auto& worm : worms) { cout << worm << " "; // 输出最终每只蚯蚓的长度 } return 0; } ``` #### 解释 上述代码实现了两种主要的操作——分裂 (`'S'`) 和生长 (`'G'`)[^1]。 - 对于 `'S'` 操作,我们根据给定的比例将某只蚯蚓分成两个较小的部分,并替换原始蚯蚓的位置。 - 对于 `'G'` 操作,则是对所有蚯蚓增加固定的增长量。 此代码片段展示了如何利用向量 `std::vector` 动态管理蚯蚓的数量及其属性的变化过程[^2]。 --- #### 进一步优化建议 为了提高效率和可维护性,还可以考虑引入 STL 中更高级的数据结构,如优先队列或集合,用于快速查找最大/最小值等情况下的操作[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值