NOIP提高组2016 蚯蚓 解题报告

题目链接

LGOJ P2827 蚯蚓

解题思路

堆维护:80pts

一看到这题,应该大部分人都会惊呼:这不就是堆的裸题吗!
好的,使用priority_queue维护就好了。至于蚯蚓的增长,在全局打个Tag就差不多了。
ok上代码(很久以前写的,风格不太一样)

详细代码

#include<cstdio>
#include<queue>
#include<cmath>
using namespace std;

int n,m,q,u,v,t;
priority_queue<int> qee;
int delta;
double p;
int main()
{
	scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&t);
	p=double(u)/v;
	for(int i=1;i<=n;i++)
	{
		int tmp;
		scanf("%d",&tmp);
		qee.push(tmp);
	}
	for(int i=1;i<=m;i++)
	{
		int l=qee.top()+delta;qee.pop();
		int l1=floor(l*p);int l2=l-l1;
		l1-=delta;l2-=delta;
		l1-=q;l2-=q;
		qee.push(l1);qee.push(l2);
		delta+=q;
		if(i%t==0) printf("%d ",l);
	}
	putchar('\n');
	for(int i=1;!qee.empty();i++)
	{
		if(i%t==0) printf("%d ",qee.top()+delta);
		qee.pop();
	}
	putchar('\n');
	return 0;
}

时间复杂度 O ( m l o g 2 n ) O(mlog_2n) O(mlog2n).应该能过80pts.不知是不是洛谷的评测机不错,跑出了个85pts

发现隐藏的结论:100pts

emmm,我们要有一双发现秘密的眼睛
我们应该注意到,如果一只蚯蚓 α \alpha α比蚯蚓 β \beta β先被切( l e n g t h α ≥ l e n g t h β length_\alpha\geq length_\beta lengthαlengthβ),那么把它们都剖开后, α \alpha α的前端长度会大于 β \beta β的前端,后端同理。
这里稍加证明:
设两只蚯蚓 α \alpha α β \beta β的长度为 a a a b b b ( a ≥ b ) (a\geq b) (ab),在 α \alpha α被切 t t t秒后, β \beta β被切成了两段。
则我们可以得到, a a a切得的新的两段的长度在过了 t t t秒后
a 1 = ⌊ a ∗ p ⌋ + t q a_1=\lfloor a*p\rfloor+tq a1=ap+tq
a 2 = a − ⌊ a ∗ p ⌋ + t q a_2=a-\lfloor a*p\rfloor+tq a2=aap+tq
b b b的新的两段为
b 1 = ⌊ p ( b + t q ) ⌋ b_1=\lfloor p(b + tq)\rfloor b1=p(b+tq)
b 2 = b + t q − ⌊ p ( b + t q ) ⌋ b_2=b+tq-\lfloor p(b + tq)\rfloor b2=b+tqp(b+tq)
我们采用做差法来比较 a 1 a_1 a1 b 1 b_1 b1
我们先忽略取整
a 1 − b 1 = a p + t q − b p − t p q a_1-b_1=ap+tq-bp-tpq a1b1=ap+tqbptpq
= ( a − b ) p + ( 1 − p ) q t =(a-b)p+(1-p)qt =(ab)p+(1p)qt
a ≥ b , 0 &lt; p &lt; 1 a\geq b,0&lt;p&lt;1 ab,0<p<1
a 1 ≥ b 1 a_1\geq b_1 a1b1
根据取整函数的性质:我们可以得到,当加上取整号时,仍有 a 1 ≥ b 1 a_1\geq b_1 a1b1
同理有 a 2 ≥ b 2 a_2\geq b_2 a2b2
所以,我们没必要用堆存储蚯蚓。我们只要根据时间,把切开的两条蚯蚓放进两个队列里,显然根据结论,这个队列里的元素会是不严格单调递减的。我们每次只要从三个队列头(还有一个队列存一次都没切的蚯蚓)找到长度最大的切开即可。其他细节与上面代码类似。

详细代码

#define USEFASTERREAD 1 

#define rg register
#define inl inline
#define DEBUG printf("[Passing [%s] in line %d.]\n", __func__, __LINE__)
#define putline putchar('\n')
#define putsp putchar(' ')
#define Rep(a, s, t) for(rg int a = s; a <= t; a++)
#define Repdown(a, t, s) for(rg int a = t; a >= s; a--)
typedef long long ll;
#include<cstdio>
#define rs freopen("test.in", "r", stdin), freopen("test.out", "w", stdout)

#if USEFASTERREAD
char In[1 << 20], *ss = In, *tt = In;
#define getchar() (ss == tt && (tt = (ss = In) + fread(In, 1, 1 << 20, stdin), ss == tt) ? EOF : *ss++)
#endif
struct IO
{
	void RS() {rs;} 
	template<typename T> inline IO r(T& x)const
	{
	    x = 0; T f = 1; char ch = getchar();
	    for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;
	    for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + int(ch - '0');
	    x *= f; return *this;
	}
	template<typename T> inline IO w(T x)const
	{
	    if(x < 0) {putchar('-'); x = -x;}
	    if(x >= 10) w(x / 10);
	    putchar(x % 10 + '0'); return *this;
	}
	template<typename T> inline IO wl(const T& x)const {w(x), putline; return *this;}
	template<typename T> inline IO ws(const T& x)const {w(x), putsp; return *this;}
	inline IO l() {putline; return *this;}
	inline IO s() {putline; return *this;}
}io;
template<typename T> inline T Max(const T& x, const T& y) {return y < x ? x : y;}
template<typename T> inline T Min(const T& x, const T& y) {return y < x ? y : x;}
template<typename T> inline void Swap(T& x, T& y) {T tmp = x; x = y; y = tmp;}
#include<queue>
#include<algorithm>
using namespace std;
const int MAXN = 100005;
const int MAXM = 7000005;
const int INF = 0x3f3f3f3f;
ll n, m, q, u, v, t;
queue<ll> Q[3];
priority_queue<int> pq;
ll a[MAXN + MAXM];
bool cmp(int a, int b) {return a > b;}
ll sum;
int main()
{
    //io.RS();
    io.r(n).r(m).r(q).r(u).r(v).r(t);
    for(rg int i = 1; i <= n; i++) io.r(a[i]);
    sort(a + 1, a + 1 + n, cmp);
    for(rg int i = 1; i <= n; i++) Q[0].push(a[i]);
    for(rg int i = 1; i <= m; i++)
    {
		ll mx = -INF, mxi = 0;
		for(rg int j = 0; j < 3; j++)
		if(!Q[j].empty() && Q[j].front() > mx) mx = Q[j].front(), mxi = j;
		ll k = Q[mxi].front(); Q[mxi].pop();
		k += sum;
		int new1 = int(k * u / v), new2 = k - new1;
		sum += q;
		new1 -= sum; new2 -= sum;
		Q[1].push(new1); Q[2].push(new2);
		if(i % t == 0) io.ws(k);
	}
	io.l();
	for(rg int i = 0; i < 3; i++)
		while(!Q[i].empty()) pq.push(Q[i].front()), Q[i].pop();
	for(rg int i = 1; !pq.empty(); i++)
	{
		if(i % t == 0) io.ws(pq.top() + sum);
		pq.pop();
	} 
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

日居月诸Rijuyuezhu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值