cf(div1+div2)构造题:D. Bouncing Boomerangs
链接:https://codeforces.com/contest/1428/problem/D
(每列最多放2个,注意读题~)
从右边向左考虑,先说结论:
a[i]=0, 不放
a[i]=1,放在(i,i)
a[i]=2,(i,i)放一个点,然后后面找一个a[j]=1(j>i)的点(且之前没被其他a[i]=2的点使用过),然后把此时在(j,j)的点上升到(i,j)
a[i]=3,(i,i)放一个点,然后后面找一个没有没有放满的列(a[j]=1的话要求没有被a[i]=2的使用过),然后在(i,j)放一个点。
口胡一波为什么这样是对的:
我们看到回旋镖的轨迹,发现a[i]=3的其实是不好考虑的,因为可能跟我之前安插的点碰撞到,那么我们让a[i]=3的最后从(i,i)走,因为(i,i)是从右下到左上不断上升的,因此可以避免。
代码:
#include<bits/stdc++.h> #define pii pair<int, int> #define fi first #define se second #define mp make_pair using namespace std; const int maxn = 1e5+7; int a[maxn]; int main() { ios::sync_with_stdio(false); cin.tie(0); int n; cin >> n; for(int i = 1; i <= n; i++) { cin >> a[i]; } int res = 0; vector<pii > vec; stack<pii > st; //a[i]=1 stack<int> st2; //没放满 bool flag = 1; for(int i = n; i >= 1; i--) { if(a[i] == 0) continue; if(a[i] == 1) { st.push(mp(i, i)); } if(a[i] == 2) { vec.push_back(mp(i, i)); st2.push(i); res++; if(!st.empty()) { pii pp = st.top(); st.pop(); res++; vec.push_back(mp(i, pp.fi)); } else { flag = 0; break; } } if(a[i] == 3) { vec.push_back(mp(i, i)); res++; if(!st2.empty()) { int tp = st2.top(); st2.pop(); vec.push_back(mp(i, tp)); res++; st2.push(i); continue; } if(!st.empty()) { pii tp = st.top(); st.pop(); vec.push_back(mp(i, tp.fi)); vec.push_back(mp(tp.fi,tp.fi)); res+=2; st2.push(i); continue; } flag = 0; break; } } if(flag) { while(!st.empty()) { pii tmp = st.top(); st.pop(); vec.push_back(tmp); res++; } cout << res << '\n'; for(auto it : vec) { cout << it.fi << " " << it.se << '\n'; } } else { cout << -1 << '\n'; } }