P7078 贪吃蛇(snakes)
说在前面
UPDATE:这里的单调性证明似乎假了,建议去【被迫营业6】观看。
考场上就打了个\(n = 3\),人傻了。
简单口胡
现在有\(n\)个蛇\(a_1,a_2,\cdots,a_n\),考虑\(a_n\)吃\(a_1\),如果:
- \(a_n - a_1 \ge a_2\),即\(a_n\)吃完后不是最小的那个,那就吃
- \(a_n - a_1 < a_2\) 如果\(a_{n - 1}\)会吃,那么\(a_n\)就不吃,否则就吃。
于是变成了递归问题。
每次要查询最小最大次小,\(\text{set}\)实现,\(\mathcal{O}(n\log{n})\)
然而加上O2快的一批(指能过)
# include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int T;
int n,k;
int ans = 0;
int cntT = 0;
struct node
{
int soc,len;
}a[N];
bool operator <(const struct node &x,const struct node &y)
{
if(x.len ^ y.len) return x.len < y.len;
else return x.soc < y.soc;
}
node operator + (const struct node &x,const struct node &y)
{
node maxl = (x < y) ? y : x;
node minl = (x < y) ? x : y;
node news;
news.len = maxl.len - minl.len;
news.soc = maxl.soc;
return news;
}
set <node> s[11];
typedef set<node>::iterator its;
bool can()
{
if(s[cntT].size() == 2)
{
return 1;
}
its head = s[cntT].begin(),head2 = s[cntT].begin(),tail = s[cntT].end();
++head2,--tail;
node New = (*tail) + (*head);
if(New < (*head2))
{
s[cntT].erase(head);
s[cntT].erase(tail);
s[cntT].insert(New);
return !can();
}
else
{
return 1;
}
}
template <typename T> void read(T &x)
{
int w = 1;
x = 0;
char ch = getchar();
while(!isdigit(ch))
{
if(ch == '-') w = -1;
ch = getchar();
}
while(isdigit(ch))
{
x = x * 10 + ch - '0';
ch = getchar();
}
x *= w;
return;
}
int main(void)
{
// freopen("P7078.in","r",stdin);
// freopen("P7078.out","w",stdout);
read(T);
while(++cntT <= T)
{
// read(n);
// s[cntT].clear();
if(cntT == 1)
{
// nn = n;
read(n);
for(int i = 1; i <= n; i++)
{
read(a[i].len);
a[i].soc = i;
s[cntT].insert(a[i]);
}
}
else
{
read(k);
for(int i = 1; i <= k; i++)
{
int x,y;
read(x),read(y);
a[x].len = y;
// printf("Yes %d\n",i);
}
// printf("11\n");
// s[cntT].clear();
// printf("22\n");
for(int i = 1; i <= n; i++)
{
// printf("a[%d] : len = %d,soc = %d\n",i,a[i].len,a[i].soc);
s[cntT].insert(a[i]);
}
}
// printf("Yes\n");
// ans = nn;
while(1)
{
its head = s[cntT].begin(),tail = s[cntT].end(),head2 = head;
++head2,--tail;
node New = (*tail) + (*head);
// printf("tail = %d,head = %d\n",(*tail).len,(*head).len);
if(New < (*head2))
{
// printf("New = %d,head2 = %d\n",New.len,(*head2).len);
break;
}
else
{
s[cntT].erase(head),s[cntT].erase(tail),s[cntT].insert(New);
}
}
ans = s[cntT].size();
// printf("ans = %d\n",ans);
if(can())
{
ans--;
}
printf("%d\n",ans);
}
return 0;
}
考虑到每次查询最大最小次小都要\(\mathcal{O}(\log{n})\)的复杂度,遂想到蚯蚓这题,维护两个队列,一个是原来的,一个是合并的,分别称为\(Q_1,Q_2\)
\(Q_1\)单调性显然,如何证明\(Q_2\)单调性?
也很简单。
考虑现在\(Q_2\)里有一个\(Max - Min\),进来一个\(Max' - Min'\),显然\(Max \ge Max',Min \le Min'\),所以\(Max - min \ge Max' - Min'\)
似乎有点牵强,但是珂以尽情猜...
我用的deque
维护,复杂度高啊,还是要加O2才能过。
# include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 4;
int n,k;
int T,cntT = 0;
template <typename T> void read(T &x)
{
int w = 1;
x = 0;
char ch = getchar();
while(!isdigit(ch))
{
if(ch == '-') w = -1;
ch = getchar();
}
while(isdigit(ch))
{
x = x * 10 + ch - '0';
ch = getchar();
}
x *= w;
return;
}
struct node
{
int soc,len;
node(){}
node(int s,int l) : soc(s),len(l) {}
}a[N];
deque <node> q[3];
typedef deque<node>::iterator its;
void print(void);
bool operator <(const struct node &x,const struct node &y)
{
if(x.len ^ y.len) return x.len < y.len;
else return x.soc < y.soc;
}
node operator + (const struct node &x,const struct node &y)
{
node maxl = (x < y) ? y : x;
node minl = (x < y) ? x : y;
node news;
news.len = maxl.len - minl.len;
news.soc = maxl.soc;
return news;
}
bool compare(const struct node &x,const struct node &y)
{
if(x.len ^ y.len) return x.len < y.len;
else return x.soc < y.soc;
}
void clear(void)
{
for(int i = 1; i <= 2; i++)
{
while(!q[i].empty()) q[i].pop_back();
}
return;
}
int Max(void)
{
node maxl;
int IT = 0;
if(q[1].empty())
{
if(!q[2].empty())
{
maxl = q[2].front();
// q[2].pop_front();
IT = 2;
return IT;
}
}
if(q[2].empty())
{
if(!q[1].empty())
{
maxl = q[1].front();
// q[1].pop_front();
IT = 1;
return IT;
}
}
if(q[1].front() < q[2].front())
{
maxl = q[2].front();
// q[2].pop_front();
IT = 2;
}
else
{
maxl = q[1].front();
// q[1].pop_front();
IT = 1;
}
return IT;
}
int Min(void)
{
node minl;
int IT;
if(q[1].empty())
{
if(!q[2].empty())
{
minl = q[2].back();
// q[2].pop_back();
IT = 2;
return IT;
}
}
if(q[2].empty())
{
if(!q[1].empty())
{
minl = q[1].back();
// q[1].pop_back();
IT = 1;
return IT;
}
}
if(q[1].back() < q[2].back())
{
minl = q[1].back();
// q[1].pop_back();
IT = 1;
}
else
{
minl = q[2].back();
// q[2].pop_back();
IT = 2;
}
return IT;
}
node Min2(void)
{
node A[5];
node tmp1 =node(n,INT_MAX),tmp2 = node(n,INT_MAX),tmp3 = node(n,INT_MAX),tmp4 = node(n,INT_MAX);
int siz1 = q[1].size(),siz2 = q[2].size();
if(!q[1].empty())
{
tmp1 = q[1][siz1 - 1];
if(siz1 >= 2) tmp2 = q[1][siz1 - 2];
}
if(!q[2].empty())
{
tmp3 = q[2][siz2 - 1];
if(siz2 >= 2) tmp4 = q[2][siz2 - 2];
}
A[1] = tmp1,A[2] = tmp2,A[3] = tmp3,A[4] = tmp4;
int NN = 4;
sort(A + 1,A + NN + 1,compare);
return A[2];
}
bool can(void)
{
// printf("can:\n");
// print();
if(q[1].size() + q[2].size() == 2) return 1;
node head = q[Min()].back(),tail = q[Max()].front(),head2 = Min2();
// printf("can : head = %d,tail = %d,head2 = %d\n",head.len,tail.len,head2.len);
node New = head + tail;
if(New < head2)
{
q[Min()].pop_back();
q[Max()].pop_front();
q[2].push_back(New);
return !can();
}
else
{
return 1;
}
}
void print(void)
{
int siz1 = q[1].size(),siz2 = q[2].size();
for(int i = 0; i < siz1; i++)
{
printf("q[1][%d] = %d\n",i + 1,q[1][i].len);
}
printf("\n");
for(int i = 0; i < siz2; i++)
{
printf("q[2][%d] = %d\n",i + 1,q[2][i].len);
}
return;
}
int main(void)
{
// freopen("P7078.in","r",stdin);
// freopen("P7078.out","w",stdout);
read(T);
while(++cntT <= T)
{
clear();
if(cntT == 1)
{
read(n);
for(int i = 1; i <= n; i++)
{
scanf("%d",&a[i].len);a[i].soc = i;
}
for(int i = n; i >= 1; i--) q[1].push_back(a[i]);
}
else
{
read(k);
for(int i = 1; i <= k; i++)
{
int x,y;
read(x),read(y);
a[x].len = y;
}
for(int i = n; i >= 1; i--) q[1].push_back(a[i]);
}
while(1)
{
// print();
node head = q[Min()].back(),tail = q[Max()].front(),head2 = Min2();
// printf("head = %d,tail = %d,head2 = %d\n",head.len,tail.len,head2.len);
node New = head + tail;
if(New < head2)
{
break;
}
else
{
q[Min()].pop_back();
q[Max()].pop_front();
q[2].push_back(New);
}
}
int ans = q[1].size() + q[2].size();
// printf("ans = %d\n",ans);
if(can()) ans--;
printf("%d\n",ans);
}
return 0;
}