読者です 読者をやめる 読者になる 読者になる

Django REST frameworkでセキュリティレベルをview毎に

Django REST framework 使ってセキュリティを強くしてると、何かしらのセキュリティがないapi叩くにも以下のエラーが出ることがある。

{
    "detail": "Authentication credentials were not provided."
}

解決法

view単位なら、

from rest_framework import viewsets, filters, permissions
class HogeViewset(viewsets.ModelViewSet):
    queryset = Hoge.objects.all()
    serializer_class = HogeSerializer
    filter_fields = (...)
    @detail_route(methods=['get'],
                  permission_classes=[permissions.AllowAny],
                  url_path='piyo')
    def piyo(self, request, pk=None):
        ...

みたいな感じで解決した。これはdetail_routeでコレータを使用した場合の例です。permission_classesを指定してあげる。ちゃんと権限は適切に。

ちなみにViewSet単位なら

from rest_framework import viewsets, filters, permissions
class HogeViewset(viewsets.ModelViewSet):
    queryset = Hoge.objects.all()
    serializer_class = HogeSerializer
    filter_fields = (...)
    permission_classes=[permissions.AllowAny]

みたいにclassのフィールドに書き足す。

Django REST framework JWT特有の現象ではないが、僕はJWT扱ってるときに困った(それまでセキュリティを指定してなかったため突然弾かれるようになってJWT特有の現象かと思って慌ててた。rest_frameworkの範囲だった。アホ。)

ubuntu 16.04 LTS に rstudioを入れようとして、「R Not Found: Unable to locate R binary by scanning standard locations」と出る

症状

rstudioをインストールした後、起動しようとすると。 "R Not Found: Unable to locate R binary by scanning standard locations" と表示される。

解決策

apt-get install r-base

なんかapt-get updateしてないと古いやつがインストールされるらしいんで予めしとくといいかも。

参考にしたやつ

support.rstudio.com

qiita.com

ubuntu 16.04 LTSのかな入力で長音(ー)が入力できない問題

またまたこの問題にぶちあたってしまいました。 インストールした当初(かな86)は正しく動作していたのに、気づいたら上手くいかなくなってたので奮闘した話。

症状

fcitx&mozcのかな入力(ローマ字でも)で、\キーを押したときの挙動が変になる。 具体的には、「ほーむ」を入力しようとしてとして「ほ「長音」む」と入力すると、「\ほむ」みたいな感じになって全くわけがわからない。

解決策

シフトキーを押しながら入力すると正しく動作するが、それは面倒くさい。 ということで、原因が何かを探ってみた。

どうやら\の挙動が変になるキーボード入力設定に一瞬でも切り替わったら、その\の挙動がmozcなどにも伝搬するらしいということが分かった(理由は探ってない)。IM(fcitx)を再起動すると治る。

これは、ログイン直後にデフォのインプットメソッドがmozcに設定されている間だけ正しく動作することから推測した。

ということで、インプットメソッド一覧にあった「キーボード 日本語(かな86)」を削除して、さらに規定のキーボードレイアウトを「日本語 - 日本語(OADG 109A)」にしてログインしなおしたら治った。

f:id:kyuridenamida:20161009103511p:plain

こんなかんじ。

振り返り

英語キーボードとかも\のキー設定をぶっ壊すっぽい。実際英語キーボード入れた後壊れた。

ところでとりあえず適当に「日本語 - 日本語(OADG 109A)」を選択したんですけど、これどれ選択するのが一番いいんですかね。

UbuntuにpycharmをLauncher(ランチャー)に登録する

pycharm.shをコンソールでもなんでもいいから起動したあと、起動中にランチャーに出てくるアイコンを右クリックして『Launcherに登録』を押せば良い。

Djangoでメールを送信しようとして出るsmtplib.SMTPAuthenticationError:

smtplib.SMTPAuthenticationErrorと出たらgoogleのセキュリティ設定が原因かもしれないので以下を確認してみましょう。

https://www.google.com/settings/security/lesssecureapps

ICPC 国内予選 2016

@a3636takoと@aki33524と出てました.8位でした. 多分通過しました.

作戦

僕が全部の問題のコーダーになって,他の二人には解法係になってもらい,基本的にペアプロをするように心がける 理由は僕が色々実装テクを知っているから早いだろうというだけ.

結果

トータルでは事無きを得たけど,恐らく失敗. この作戦は,バグがない場合に限り有効であることが分かった.バグが発生したとき,死亡する. 普通のバグは大体潰してもらえるのだけれど,見落としがちな論理的なバグはペアプロでも潰しようがない.

具体的には,A・BをFAして1位に踊りでた後,Dでバグらせた上に,デバッグ放棄してCの実装をしたので順位がヤバいことになった. その間チームメイトにバグを探してもらったけど見つからなくて,結局論理的に間違っていることが分かった. 黄色コーダー級のチームメイトが2人いるのだから,簡単な問題を実装してもらいつつ僕がデバッグをしてもよかった.

僕しかパソコンに触らない状況だと,僕がデバッグするときに全くパソコンが開かない.

今後

アジア地区予選に向けて,この作戦を適用できるかどうかは再度考慮しないといけない. 少なくともアジア地区は解法がすぐに降ってくるタイプの問題が少ないので,パソコンの前をできるだけ無駄に空けたくない. ということで,コーダー2人体制とか3人体制とかいろいろ試してみようと思います.

悩み

僕がチームの中で飛び抜けているのは経験に基づく解法力のみで,やはり思考力がないので,そこを伸ばしていきたい. 経験により実力は誤魔化せるけど,頭の回転の遅さは何年経っても改善しないのをうっすら感じる. 「典型レパートリーを無限に増やし続けるのだ」という某の言説が聞こえてきますが,それを早くこなすようなガッツも時間も能力もないので,やっぱりそういうことができるのは強い人だと思います(やや悲観的).

ICPC2016 模擬国内予選B

A

日本語を読む

紛失

B

グイッと実装.stringstreamは便利

#include <bits/stdc++.h>
using namespace std;

// 頭が整理されてないまま書いた糞コード

int main(){
    string S;
    int a,b,c,d;
    while( cin >> S && S != "#" ){
        cin >> a >> b >> c >> d;

        for(int i = 0 ; i < S.size() ; i++){
            if( S[i] == '/' ) S[i] = ' ';
        }
        vector<string> to;
        stringstream ss(S);
        string t;
        while( ss >> t ){
            string a;
            for( auto c : t ){
                if( '0' <= c && c <= '9' ){
                    a += string(c-'0',' ');
                }else{
                    a += c;
                }
            }
            to.push_back(a);
        }
        swap(to[a-1][b-1],to[c-1][d-1]);
        string ans;
        for( auto l : to ){
            string a = "";
            for(int i = 0 ; i < l.size() ; ){
                if( l[i] == 'b' ) a += 'b', i++;
                else{
                    int j = i;
                    while( j < l.size() and l[j] == ' ' ) j++;
                    a += '0'+j-i;
                    i = j;
                }
            }
            ans += a + "/";
        }
        cout << ans.substr(0,ans.size()-1) << endl;
    }
}

C

座圧してセルの内外判定する気が起きなかったので平面走査

#include <bits/stdc++.h>
using namespace std;
// 計算量は O(N+窓の周長)

int main(){
    int N;
    while( cin >> N && N){
        map<int,vector< pair<int,int> > > seg;
        for(int i = 0 ; i < 50000 ; i++) seg[i] = {};
        
        
        //(1) 窓の入力 & x軸に平行な線分のみをy座標毎に列挙
        int px,py;
        int sx,sy;
        for(int i = 0 ; i < N ; i++){
            int x,y;
            cin >> x >> y;
            x += 20000;
            y += 20000;
            if(i){
                if( y == py ){
                    int a = x;
                    int b = px;
                    if( b < a ) swap(a,b);
                    seg[y].push_back({a,b});
                }
            }else sx = x, sy = y;
            px = x;
            py = y;
        }
        if( sy == py ){
            int a = sx;
            int b = px;
            if( b < a ) swap(a,b);
            seg[sy].push_back({a,b});
        }
        
        // (2) カーテンの入力 & カーテンの範囲を求める
        int x1 = 1e9,x2 = -1e9,y1 = 1e9,y2 = -1e9;
        for(int i = 0 ; i < 4 ; i++){
            int x,y;
            cin >> x >> y;
            x += 20000;
            y += 20000;
            x1 = min(x1,x);
            x2 = max(x2,x);
            y1 = min(y1,y);
            y2 = max(y2,y);
        }
        // 平面走査 & 正直あんましimosしてない
        vector<int> imos(50000);
        long long allans = 0;
        long long innerans = 0;
        long long innertot = 0;
        long long alltot = 0;
        
        for( auto vec : seg){                               
            int y = vec.first;
            for(auto s : vec.second ){
                for(int x = s.first ; x < s.second ; x++){
                    imos[x] ^= 1;
                    // for inner 
                    if( (x1 <= x and x < x2) ){
                        if( imos[x] ) innertot += 1;
                        else innertot -= 1;
                    }
                    // for all
                    if( imos[x] ) alltot += 1;
                    else alltot -= 1;
                }
            }
            // for all
            allans += alltot;
            // for inner
            if( (y1 <= y && y < y2) ){
                innerans += innerans;
            }
        }
        cout << allans - innerans  << endl;
    }
}

D

本質は強連結成分分解なのですが,O(N+M)のアルゴリズム使わなくてもO(N3)のワーシャルフロイドっぽい実装で代替できます(N:頂点数,M:辺数).

#include <bits/stdc++.h>
using namespace std;

int main(){
    int N;
    while(cin >> N && N){
        bool g[110][110]={};
        bool g_src[110][110]={};
        int in[110] = {};
        double p[110];
        for(int i = 0 ; i < N ; i++){
            int m;
            cin >> p[i] >> m;
            while(m--){
                int j;
                cin >> j;
                --j;
                g[i][j] = true;
                g_src[i][j] = true;
            }
        }
        
        for(int i = 0 ; i < N ; i++)
            g[i][i] = true;
        for(int i = 0 ; i < N ; i++)
            for(int j = 0 ; j < N ; j++)
                for(int k = 0 ; k < N ; k++)
                    g[j][k] |= g[j][i] & g[i][k];
        bool used[110] = {};
        int color[110] = {};
        double p_to_col[110] = {};
        
        // 強連結成分分解
        for(int i = 0 ; i < N ; i++){
            if( used[i] ) continue;
            double bad = 1.0;
            for(int j = 0 ; j < N ; j++){
                if( used[j] == false and g[i][j] && g[j][i] ){
                    bad *= p[j];
                    used[j] = true;
                    color[j] = i;
                }
            }
            p_to_col[i] = bad;
        }
        // 入次数数える
        for(int i = 0 ; i < N ; i++){
            for(int j = 0 ; j < N ; j++){
                if( g_src[i][j] and color[i] != color[j] ){
                    in[j]++;
                }
            }
        }
        
        // 入次数0の頂点のみに着目
        double ans = 1.0;
        for(int i = 0 ; i < N ; i++){
            if( in[i] == 0 and color[i] == i ){
                ans *= 1 - p_to_col[i];
            }
        }
        printf("%.10lf\n",ans);

    }
}

E

よく考えるとdはソートしてよさそうなのでソートすると,布団を片付けることを一切考えなくて良い状態になってハッピー. 頭が悪いので遷移に全ての部分集合をぶち込んでいるが,遷移を工夫すれば計算量落ちます.

#include <bits/stdc++.h>
using namespace std;
// O(M*3^N)

int s[110],d[110];
int N,M;

int dp[110][1<<16];

vector<int> bit[1<<15];
int sum[1<<16];

int dfs(int x,int bit){
    if( x == M ) return 0;
    if( dp[x][bit] != -1 ) return dp[x][bit];

    int ans = 1e9;
    /*for(int i = 0 ; i < (1<<N) ; i++){
        if( bit & i ) continue;
        ans = min(dfs(x+1,bit|i)+abs(sum[i|bit]-d[x]),ans); 
    }*/
    // 上と下は等価
    int sup = ((1<<N)-1)^bit;
    int i = sup;
    do{
        ans = min(dfs(x+1,bit|i)+abs(sum[i|bit]-d[x]),ans);
        i = (i-1)&sup;
    } while( i != sup );
    
    return dp[x][bit] = ans;
}
int main(){
    int t = 0;
    while( cin >> N >> M && N ){
        memset(dp,-1,sizeof(dp));
        for(int i = 0 ; i < N ; i++) cin >> s[i];
        for(int i = 0 ; i < M ; i++) cin >> d[i];
        for(int i = 0 ; i < (1<<N) ; i++){
            int t = 0;
            for(int j = 0 ; j < N ; j++){
                if( i >> j & 1 ){
                    t += s[j];
                }
            }
            sum[i] = t;
        }
        sort(d,d+M);
        cout << dfs(0,0) << endl;


    }
}

G

全てきひろちゃんとa3636takoが考えた.実装しただけ.

#include <bits/stdc++.h>
using namespace std;

long long mod = (int)1e9 + 7;

long long b_pow(long long a,long long b){
    return b ? b_pow(a*a%mod,b/2) * (b&1?a:1) % mod : 1;
}

#define CCCCCC 4000000
long long f[4000010];
long long inv[4000010];

long long ncr(long long a,long long b){
    //cout << a << " " << b << endl;
    assert( b <= a );

    return f[a] * inv[a-b] % mod * inv[b] % mod;
}
int main(){

    // N!とN!の逆元を全て求めとく
    f[0] = 1;
    for(int i = 1 ; i <= CCCCCC ; i++)
        f[i] = f[i-1] * i % mod;
    for(int i = 0 ; i <= CCCCCC ; i++)
        inv[i] = b_pow(f[i],mod-2);
        
    int A,B,C,Sx,Sy;
    while( cin >> A >> B >> C >> Sx >> Sy and A+B+C ){
        if( A == 0 and B == 0 ){
            if( Sx != Sy ) cout << 0 << endl;
            else cout << ncr( Sx + C - 1, C - 1 ) << endl;
            continue;
        }

        if( A == 0 ){
            swap(A,B);
            swap(Sx,Sy);
        }
        long long ans;
        if( B == 0 ){
            ans = ncr(Sx-Sy-1,A-1) * ncr( (A+C-1) + Sy, A+C-1) % mod;
        }else{
            ans = 0;
            for(int a = A ; a <= Sx ; a++){
                long long X = ncr(a+A-1-A,A-1);
                int b = Sy - Sx + a;
                if( b < B ) continue;

                long long Y = ncr(b+B-1-B,B-1);
                long long Z = ncr( (A+B+C-1) + (Sx-a), A+B+C-1);

                ans += X * Y % mod * Z % mod;
                ans %= mod;
            }
        }
        cout << ans * f[A+B+C] % mod * inv[A] % mod * inv[B] % mod * inv[C] % mod << endl;  
    }
}