P7078 貪吃蛇(snakes)
阿新 • • 發佈:2020-11-29
說在前面
考場上就打了個\(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; }