結果
問題 | No.190 Dry Wet Moist |
ユーザー |
![]() |
提出日時 | 2016-01-10 20:57:52 |
言語 | C++11 (gcc 13.3.0) |
結果 |
AC
|
実行時間 | 289 ms / 2,000 ms |
コード長 | 3,311 bytes |
コンパイル時間 | 1,373 ms |
コンパイル使用メモリ | 166,696 KB |
実行使用メモリ | 13,440 KB |
最終ジャッジ日時 | 2024-09-19 15:59:01 |
合計ジャッジ時間 | 4,831 ms |
ジャッジサーバーID (参考情報) |
judge1 / judge5 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 2 |
other | AC * 28 |
ソースコード
#include <bits/stdc++.h>typedef long long ll;typedef unsigned long long ull;#define FOR(i,a,b) for(int (i)=(a);i<(b);i++)#define REP(i,n) FOR(i,0,n)#define RANGE(vec) (vec).begin(),(vec).end()using namespace std;class DryWetMoist {public:void solve(void) {int N;cin>>N;vector<int> A(2*N);REP(i,2*N) cin>>A[i];// まともに計算すると O(N!) になってしまう。//// まず Moist を最大化する組み合わせに注目する// Moist になるには (a,-a) なる組み合わせしかありえないので、// 貪欲法で計算すればよい。ソートしておけば O(N*log(N)) で計算できる。//// 同様に Dry なものを作るには貪欲法で a<0 のとき (a,b) (b<-a なる最大の b)// Wet なものを作るには a>0 のとき (a,b) (b>-a なる 最小の b)// なる b を選べば良い。// これらも二分探索で O(N*log(N)) でみつかる//// multiset をつかえば配列の要素の削除・更新ができる。//int nDry = 0;{multiset<int> S(RANGE(A));while (!S.empty()){auto beg = S.begin();int a = *beg;if (a >= 0)break;S.erase(beg); // 重複検索しないように先に削除auto found = S.lower_bound(-a);if (found != S.begin()){--found;assert(a+*found <0);++nDry;S.erase(found);}}}int nWet = 0;{multiset<int> S(RANGE(A));while (!S.empty()){// 大きいものから取り出すauto it = S.end();--it;int a = *it;if (a < 0)break;S.erase(it);auto found = S.upper_bound(-a);if (found != S.end() && a + *found > 0){++nWet;S.erase(found);}}}int nMoist = 0;{multiset<int> S(RANGE(A));while (!S.empty()){auto beg = S.begin();int a = *beg;S.erase(beg);auto found = S.lower_bound(-a);if (found != S.end() && *found == -a){++nMoist;S.erase(found);}}}cout<<nDry<<" "<<nWet<<" "<<nMoist<<endl;}};#if 1int main(int argc, char *argv[]){ios::sync_with_stdio(false);auto obj = new DryWetMoist();obj->solve();delete obj;return 0;}#endif