AOJ 0552 - Exposition

コードがやばい.

解法

(x, y) -> (x+y, x-y)という変換(45度回転)をすると,施設iと施設jの距離は
max{|x[i]-x[j]|, |y[i]-y[j]|}
と表されます.以下,変換後の座標系で話をすすめます.
まず,x座標とy座標で幅の広い方(最小値と最大値の差が大きい方.同じときはどちらでもいい)を選び,その座標の最小値と最大値を求める.
この2つが同じテーマだと,どう頑張っても最長になってしまうので違うテーマに分けてあげます.
その後,各テーマで(最小/最大)の(x座標/y座標)をもちながら,次のようにテーマを割り振る.
それぞれのテーマで最も遠い施設を求め,より距離が遠い方(同じときはどちらでもよい)を,他方のテーマに割り当てる.
すべての施設を割り当てたとき,2つのテーマの(x座標/y座標)の最小・最大の差の大きい方が答えになります.

x座標とy座標で幅の広い方,最も遠い点はどう求めたらいいでしょうか.距離の式がx座標,y座標について分離しているので,x座標でソートしたもの,y座標でソートしたものがあるといいですね.さらに,削除がある程度速いといいですね.これって何てstd::set.(なお,特別なデータ構造をつかわなくても解ける模様.)

コード

Ω\・8・)チューン

// ナニソレイミワカンナイ

#include <cstdio>
#include <vector>
#include <algorithm>
#include <set>
#include <tuple>

typedef std::pair<int,int> P;
typedef std::tuple<P,bool,int> Q;
std::set<P> setX, setY;
int N;

Q f(int mnX, int mxX, int mnY, int mxY){
    P p = *setX.begin();
    bool isX = true;
    int l = std::max(std::abs(mnX-p.first),
                     std::abs(mxX-p.first));

    P _p;
    int _l;
    _p = *setX.rbegin();
    if((_l = std::max(std::abs(mnX-_p.first),
                      std::abs(mxX-_p.first))) > l){
        p = _p;
        l = _l;
    }

    _p = *setY.begin();
    if((_l = std::max(std::abs(mnY-_p.first),
                      std::abs(mxY-_p.first))) > l){
        p = _p;
        l = _l;
        isX = false;
    }

    _p = *setY.rbegin();
    if((_l = std::max(std::abs(mnY-_p.first),
                      std::abs(mxY-_p.first))) > l){
        p = _p;
        l = _l;
        isX = false;
    }

    return std::make_tuple(p, isX, l);
}

int main(){
    scanf("%d", &N);

    for(int i=0;i<N;i++){
        int x, y;
        scanf("%d %d", &x, &y);

        int x_ = x+y, y_ = x-y;
        setX.insert(std::make_pair(x_, y_));
        setY.insert(std::make_pair(y_, x_));
    }

    int mnX1, mxX1, mnY1, mxY1,
        mnX2, mxX2, mnY2, mxY2;
    if(setX.rbegin()->first-setX.begin()->first >
       setY.rbegin()->first-setY.begin()->first){
        mnX1 = setX.begin()->first;
        mxX1 = mnX1;
        mnY1 = setX.begin()->second;
        mxY1 = mnY1;
        mnX2 = setX.rbegin()->first;
        mxX2 = mnX2;
        mnY2 = setX.rbegin()->second;
        mxY2 = mnY2;

        P p1 = *setX.begin(), p2 = *setX.rbegin();
        setY.erase(std::make_pair(p1.second, p1.first));
        setY.erase(std::make_pair(p2.second, p2.first));
        setX.erase(p1);
        setX.erase(p2);
    }else{
        mnX1 = setY.begin()->second;
        mxX1 = mnX1;
        mnY1 = setY.begin()->first;
        mxY1 = mnY1;
        mnX2 = setY.rbegin()->second;
        mxX2 = mnX2;
        mnY2 = setY.rbegin()->first;
        mxY2 = mnY2;

        P p1 = *setY.begin(), p2 = *setY.rbegin();
        setX.erase(std::make_pair(p1.second, p1.first));
        setX.erase(std::make_pair(p2.second, p2.first));
        setY.erase(p1);
        setY.erase(p2);
    }
    
    for(;!setX.empty();){
        Q q1 = f(mnX1, mxX1, mnY1, mxY1),
          q2 = f(mnX2, mxX2, mnY2, mxY2);

        if(std::get<2>(q1) > std::get<2>(q2)){
            mnX2 = std::min(mnX2, std::get<1>(q1) ? std::get<0>(q1).first : std::get<0>(q1).second);
            mxX2 = std::max(mxX2, std::get<1>(q1) ? std::get<0>(q1).first : std::get<0>(q1).second);
            mnY2 = std::min(mnY2, std::get<1>(q1) ? std::get<0>(q1).second : std::get<0>(q1).first);
            mxY2 = std::max(mxY2, std::get<1>(q1) ? std::get<0>(q1).second : std::get<0>(q1).first);

            setX.erase(std::get<1>(q1) ? std::get<0>(q1) : std::make_pair(std::get<0>(q1).second, std::get<0>(q1).first));
            setY.erase(std::get<1>(q1) ? std::make_pair(std::get<0>(q1).second, std::get<0>(q1).first) : std::get<0>(q1));
        }else{
            mnX1 = std::min(mnX1, std::get<1>(q2) ? std::get<0>(q2).first : std::get<0>(q2).second);
            mxX1 = std::max(mxX1, std::get<1>(q2) ? std::get<0>(q2).first : std::get<0>(q2).second);
            mnY1 = std::min(mnY1, std::get<1>(q2) ? std::get<0>(q2).second : std::get<0>(q2).first);
            mxY1 = std::max(mxY1, std::get<1>(q2) ? std::get<0>(q2).second : std::get<0>(q2).first);

            setX.erase(std::get<1>(q2) ? std::get<0>(q2) : std::make_pair(std::get<0>(q2).second, std::get<0>(q2).first));
            setY.erase(std::get<1>(q2) ? std::make_pair(std::get<0>(q2).second, std::get<0>(q2).first) : std::get<0>(q2));
        }
        
    printf("%d\n", std::max({mxX1-mnX1, mxY1-mnY1,
                    mxX2-mnX2, mxY2-mnY2}));
}

ORSolitaire - TopCoder SRM Div1 #600 Easy

これは解ける.223.84pt(Practice)

解法

まず,各整数がgoalをつくるのに使えるかを調べる.
整数nがn | ~goal = 0を満たすならば,nはgoalをつくるのに使える.
(等式を満たさないならば,goalにない1の立つビットができてしまう.)
満たす整数のORをとり,goalにならなければ,そもそもできないので,0を出力する.
そうでなければ,goalの1であるビットに着目する.そのビットが1である整数をすべて削除すれば,goalをつくることはできない.よって,各ビットに対し,そこが1である整数を数えて,その最小の個数を求めればいい.

コード

class ORSolitaire {
public:
    int getMinimum(vector<int> numbers, int goal) {
        int x = 0;
        std::vector<int> v;
        for(int n : numbers){
            if(n & ~goal){continue;}
            x |= n;
            v.push_back(n);
        }

        if(x != goal){return 0;}
        
        int res = 252521;
        for(int i=0;i<=30;i++){
            if(!(goal >> i & 1)){continue;}
            int c = 0;
            for(int j : v){
                if(j >> i & 1){++c;}
            }
            res = std::min(res, c);
        }

        return res;
    }
};

不定期やるだけ(AOJ)

やるだけ.

Flick Input(AOJ 2417)

時代を感じる.

#include <iostream>

std::string table = "  kstnhmyr", table2 = "aiueo", table3 = "TLURD";

int main(){
    std::string S, T = "";
    std::cin >> S;
    for(int i=0;i<S.size();i+=2){
        if(S[i] == '0'){
            if(S[i+1] == 'T'){T += "wa";}
            else if(S[i+1] == 'D'){T += "wo";}
            else{T += "nn";}
        }else if(S[i] == '1'){
            T += table2[table3.find(S[i+1])];
        }else{
            T += table[S[i]-'0'];
            T += table2[table3.find(S[i+1])];
        }
    }

    std::cout << T << std::endl;
}

Kagisys(AOJ 2440)

unordered_mapで殴る.

#include <iostream>
#include <unordered_map>

std::unordered_map<std::string, int> m;

int main(){
    int N;
    std::cin >> N;

    for(int i=0;i<N;i++){
        std::string key;
        std::cin >> key;

        ++m[key];
    }

    int M;
    std::cin >> M;

    bool locked = true;
    for(int i=0;i<M;i++){
        std::string id;
        std::cin >> id;

        if(m[id] > 0){
            if(locked){
                std::cout << "Opened by " << id << std::endl;
            }else{
                std::cout << "Closed by " << id << std::endl;
            }
            locked ^= 1;
        }else{
            std::cout << "Unknown " << id << std::endl;
        }
    }
}

Parentheses(AOJ 2490)

同じ問題3回ぐらいみた.

#include <iostream>

int N;

bool solve(){
    int opened = 0;
    for(int i=0;i<N;i++){
        char c;
        int n;
        std::cin >> c >> n;

        if(c == '('){
            opened += n;
        }else{
            if(n > opened){return false;}
            opened -= n;
        }
    }

    return opened == 0;
}

int main(){
    std::cin >> N;

    std::cout << (solve() ? "YES" : "NO") << std::endl;
}

Summer of KMC(AOJ 2216)

コミケ行ってみたい.

#include <cstdio>

int main(){
    int A, B;
    while(scanf("%d %d", &A, &B), A || B){
        B -= A;
        printf("%d %d %d\n", B % 500 / 100, B % 1000 / 500, B / 1000);
    }
}

koukyoukoukokukikou(AOJ 2252)

the やるだけって感じ.

#include <iostream>

int main(){
    std::string right = "yuiophjklnm";
    std::string S;
    while(std::cin >> S, S != "#"){
        int prev = -1, res = 0;
        for(const auto &c : S){
            int which = right.find(c) != std::string::npos;
            if(prev == -1){
                prev = which;
            }else if(which != prev){
                ++res; prev = which;
            }
        }

        printf("%d\n", res);
    }
}

KUPC(AOJ 2271)

JOI Emblem.

#include <iostream>
#include <algorithm>

int count[26];

int main(){
    std::string S;
    std::cin >> S;

    for(const auto& c : S){
        if(std::islower(c)){continue;}
        ++count[c&63];
    }

    printf("%d\n", std::min({count['K'&63], count['U'&63], count['P'&63], count['C'&63]}));
}

Palindromic Number(AOJ 2489)

疲れてきた.

#include <iostream>

bool isPalindromic[10002];
int A[10002], B[10002];

int main(){
    for(int i=0;i<=10001;i++){
        std::string s = std::to_string(i);
        bool f = true;
        for(int j=0;j<s.size();j++){
            if(s[j] != s[s.size()-1-j]){f = false; break;}
        }
        if(f){isPalindromic[i] = true;}
    }
    
    int prev;
    for(int i=0;i<=10001;i++){
        if(isPalindromic[i]){prev = i;}
        A[i] = prev;
    }

    for(int i=10001;i>=0;i--){
        if(isPalindromic[i]){prev = i;}
        B[i] = prev;
    }
    
    int N;
    std::cin >> N;

    if(std::abs(N-A[N]) <= std::abs(N-B[N])){
        std::cout << A[N]<< std::endl;
    }else{
        std::cout << B[N]<< std::endl;
    }
    
}

Programming Contest(AOJ 2259)

YukiCoderは偉大.(49byte)

gets;p$<.map{|s|s.split.map(&:to_i).inject:+}.max

AOJ 2407 - Simple Othello

ふんふむ.

解法

かたまりで見る.
例. ooxox -> oxox, xoooox -> xox
(1) かたまりが1つ(o, x)
両者はパスするしかないので,そのかたまりの色の方が勝つ.

(2) かたまりが偶数個
oが勝つ.

(3) かたまりが奇数個
端っこの色のほうが勝つ.
例. oxoxo -> oの勝ち,xox -> xの勝ち

コード

#include <iostream>

int main(){
    std::string S;
    std::cin >> S;

    char prev = '*';
    int l = 0;
    for(const char &c : S){
        if(c != prev){
            ++l; prev = c;
        }
    }

    if(l == 1 || l & 1){
        std::cout << S[0] << std::endl;
    }else{
        std::cout << 'o' << std::endl;
    }
}

AOJ 2408 - Social

うさぎ社会の闇.

解法

やるだけ.

コード

#include <cstdio>

int main(){
    int N, K;
    scanf("%d %d", &N, &K);

    int M[50], bunny[50][50];
    for(int i=0;i<K;i++){
        scanf("%d", M+i);

        for(int j=0;j<M[i];j++){
            scanf("%d", &bunny[i][j]);
            --bunny[i][j];
        }
    }

    int R, d[50][50];
    scanf("%d", &R);
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            d[i][j] = 0;
        }
    }
    for(int i=0;i<R;i++){
        int p, q;
        scanf("%d %d", &p, &q);
        --p; --q;
        
        d[p][q] = 1;
        d[q][p] = 1;
    }
    
    int res = 0;
    for(int i=0;i<K;i++){
        for(int j=0;j<M[i];j++){
            for(int k=0;k<M[i];k++){
                if(d[bunny[i][j]][bunny[i][k]]){++res; break;}
            }
        }
    }

    printf("%d\n", res);
}

AOJ 2254 - Fastest Route

やるだけ.

解法

bitDP.

コード

たまにはループで.

#include <cstdio>
#include <algorithm>

int T[16][17], T_[1<<16][16];
int dp[1<<16][16];

int main(){
    int N;
    while(scanf("%d", &N), N){
        for(int i=0;i<N;i++){
            for(int j=0;j<=N;j++){
                scanf("%d", &T[i][j]);
            }
        }

        for(int i=0;i<1<<N;i++){
            for(int j=0;j<N;j++){
                int mn = T[j][0];
                for(int k=0;k<N;k++){
                    if(!(i >> k & 1)){continue;}
                    mn = std::min(mn, T[j][k+1]);
                }
                T_[i][j] = mn;
            }
        }

        for(int i=0;i<1<<N;i++){
            for(int j=0;j<N;j++){
                dp[i][j] = i == 0 ? 0 : 1001001001;
            }
        }

        for(int i=0;i<1<<N;i++){
            for(int j=0;j<N;j++){
                for(int k=0;k<N;k++){
                    if(i >> k & 1){continue;}
                    int ni = i | (1 << k);
                    dp[ni][k] = std::min(dp[ni][k], dp[i][j] + T_[i][k]);
                }
            }
        }

        int res = 1001001001;
        for(int i=0;i<N;i++){
            res = std::min(res, dp[(1<<N)-1][i]);
        }

        printf("%d\n", res);
    }
}

AOJ 2009 - Area Separation

毎回どうだっけってなる.

解法

1本ずつ直線を足していく.(今までの直線(正方形の辺を含む)と加えた直線の交点)-1だけ領域が増える.但し,正方形内にない交点は含まない.
重複して数えないよう注意する.例えば,
f:id:TOTTORIPAPER:20150318010545p:plain
から
f:id:TOTTORIPAPER:20150318010551p:plain
のように直線を加えたとき,交点は3つである.

コード

ライブラリの部分は省略しています.

#include <cstdio>
#include <algorithm>

double EPS = 1e-9;

int N;
bool used[25252];
P line[104][2];

int main(){
    line[0][0] = {-100.0, -100.0};
    line[0][1] = {-100.0, 100.0};
    line[1][0] = {-100.0, 100.0};
    line[1][1] = {100.0, 100.0};
    line[2][0] = {100.0, 100.0};
    line[2][1] = {100.0, -100.0};
    line[3][0] = {100.0, -100.0};
    line[3][1] = {-100.0, -100.0};
    
    while(scanf("%d", &N), N){
        for(int i=4;i<N+4;i++){
            double x1, y1, x2, y2;
            scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2);

            line[i][0].real(x1);
            line[i][0].imag(y1);
            line[i][1].real(x2);
            line[i][1].imag(y2);
        }

        std::vector<P> v{{-100, -100}, {-100, 100}, {100, 100}, {100, -100}};
        int res = 1;
        for(int i=4;i<N+4;i++){
            for(int j=0;j<25252;j++){used[j] = false;}
            
            for(int j=0;j<i;j++){
                if(areIntersectedLines(line[i][0], line[i][1], line[j][0], line[j][1])){
                    P p = intersection(line[i][0], line[i][1], line[j][0], line[j][1]);
                    double x = real(p), y = imag(p);
                    if(x < -100.0 - EPS || x > 100.0 + EPS || y < -100.0 - EPS || y > 100.0 + EPS){continue;}

                    bool f = true;
                    for(int k=0;k<v.size();k++){
                        if(std::abs(dist(p-v[k])) < 1e-10){
                            if(!used[k]){used[k] = true; res++;}
                            f = false;
                            break;
                        }
                    }
                    if(f){res++; v.push_back(p);}
                }
            }
            res--;
        }

        printf("%d\n", res);
    }