提出 #45351007


ソースコード 拡げる

#include <iostream> // cout, endl, cin
#include <string> // string, to_string, stoi
#include <vector> // vector
#include <algorithm> // min, max, swap, sort, reverse, lower_bound, upper_bound
#include <utility> // pair, make_pair
#include <tuple> // tuple, make_tuple
#include <cstdint> // int64_t, int*_t
#include <cstdio> // printf
#include <map> // map
#include <queue> // queue, priority_queue
#include <set> // set
#include <stack> // stack
#include <deque> // deque
#include <unordered_map> // unordered_map
#include <unordered_set> // unordered_set
#include <bitset> // bitset
#include <cctype> // isupper, islower, isdigit, toupper, tolower
#include <iomanip>
#include <climits>
#include <cmath>
#include <functional>
#include <numeric>
#include <regex>
#include <array>
#include <fstream>
#include <sstream>

//#include<atcoder/modint>
//using namespace atcoder;

#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define rep1(i, n) for (int i = 1; i <= (int)(n); i++)
#define repl(i,l,r) for (int i = l; i < (int)(r); i++)
#define all(a) a.begin(),a.end()
#define Pii pair<int,int>
#define Pll pair<long,long>
#define INFi 1000000001
#define INFl 1000000000000000001
#define ll long long
using namespace std;



template<class T> inline bool chmin(T& a, T b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
template<class T> inline bool chmax(T& a, T b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}

template<class T> void printArray(vector<T>&A){
    for(T&a:A){
        cout<<a<<" ";
    }
    cout<<endl;
}
template<class T> void printArrayln(vector<T>&A){
    for(T&a:A){
        cout<<a<<endl;
    }
}


template<class T1,class T2> std::ostream &operator<<(std::ostream &out, const pair<T1,T2> &A){
    cout<<"{"<<A.first<<","<<A.second<<"}";
    return out;
}

template<class T1,class T2> std::ostream &operator<<(std::ostream &out, const map<T1,T2> &M){
    for(const auto&A:M){
        cout<<"{"<<A.first<<","<<A.second<<"}";
    }
    return out;
}

template<class T1> std::ostream &operator<<(std::ostream &out, const set<T1> &M){
    cout<<"{";
    for(const auto&A:M){
        cout<<A<<", ";
    }
    cout<<"}"<<endl;
    return out;
}


template<class T1> std::ostream &operator<<(std::ostream &out, const multiset<T1> &M){
    cout<<"{";
    for(const auto&A:M){
        cout<<A<<", ";
    }
    cout<<"}"<<endl;
    return out;
}

template<class T> std::ostream &operator<<(std::ostream &out, const vector<T> &A){
    for(const T &a:A){
        cout<<a<<" ";
    }
    return out;
}

void print() { cout << endl; }
 
template <typename Head, typename... Tail>
void print(Head H, Tail... T) {
  cout << H << " ";
  print(T...);
}


template<class T> std::istream &operator>>(std::istream &in,vector<T>&A){
    for(T&a:A){
        std::cin>>a;
    }
    return in;
}

// modint: mod 計算を int を扱うように扱える構造体
template<int MOD> struct Fp {
    long long val;
    constexpr Fp(long long v = 0) noexcept : val(v % MOD) {
        if (val < 0) val += MOD;
    }
    constexpr int getmod() { return MOD; }
    constexpr Fp operator - () const noexcept {
        return val ? MOD - val : 0;
    }
    constexpr Fp operator + (const Fp& r) const noexcept { return Fp(*this) += r; }
    constexpr Fp operator - (const Fp& r) const noexcept { return Fp(*this) -= r; }
    constexpr Fp operator * (const Fp& r) const noexcept { return Fp(*this) *= r; }
    constexpr Fp operator / (const Fp& r) const noexcept { return Fp(*this) /= r; }
    constexpr Fp& operator += (const Fp& r) noexcept {
        val += r.val;
        if (val >= MOD) val -= MOD;
        return *this;
    }
    constexpr Fp& operator -= (const Fp& r) noexcept {
        val -= r.val;
        if (val < 0) val += MOD;
        return *this;
    }
    constexpr Fp& operator *= (const Fp& r) noexcept {
        val = val * r.val % MOD;
        return *this;
    }
    constexpr Fp& operator /= (const Fp& r) noexcept {
        long long a = r.val, b = MOD, u = 1, v = 0;
        while (b) {
            long long t = a / b;
            a -= t * b; swap(a, b);
            u -= t * v; swap(u, v);
        }
        val = val * u % MOD;
        if (val < 0) val += MOD;
        return *this;
    }
    constexpr bool operator == (const Fp& r) const noexcept {
        return this->val == r.val;
    }
    constexpr bool operator != (const Fp& r) const noexcept {
        return this->val != r.val;
    }
    friend constexpr ostream& operator << (ostream &os, const Fp<MOD>& x) noexcept {
        return os << x.val;
    }
    friend constexpr Fp<MOD> modpow(const Fp<MOD> &a, long long n) noexcept {
        if (n == 0) return 1;
        auto t = modpow(a, n / 2);
        t = t * t;
        if (n & 1) t = t * a;
        return t;
    }
};








using mint = Fp<1000000007>;

mint dp[3001][3001][2][2];

vector<mint> f(int n){
    if(n==1){
        return vector<mint>{mint(1), mint(1)};
    }
    rep(i,3001)rep(j,3001)rep(k,2)rep(l,2)dp[i][j][k][l] = mint(0);
    // nはサイクルの長さ
    // dp[i][j][k][l] :=
    // i番目までの辺を見て、j個使ったとき、
    // k=0: 直前を使っていない k=1: 直前を使った
    // l=0: 0を使っていない l=1: 0を使った
    dp[0][0][0][0] = 1;
    for(int i=1;i<=n;i++){
        for(int j=0;j<=n;j++){
            if(i==1){
                // 使わない
                dp[i][j][0][0] += dp[i-1][j][0][0];
                if(j>0){
                    // 前を使う
                    dp[i][j][0][1] += dp[i-1][j-1][0][0];
                    // 後ろを使う
                    dp[i][j][1][0] += dp[i-1][j-1][0][0];
                }
            }else if(i==n){
                // 使わない
                dp[i][j][0][0] += dp[i-1][j][0][0];
                dp[i][j][0][0] += dp[i-1][j][1][0];
                dp[i][j][0][1] += dp[i-1][j][0][1];
                dp[i][j][0][1] += dp[i-1][j][1][1];
                if(j>0){
                    // 前を使う
                    dp[i][j][0][0] += dp[i-1][j-1][0][0];
                    dp[i][j][0][1] += dp[i-1][j-1][0][1];
                    // 後ろを使う
                    dp[i][j][1][0] += dp[i-1][j-1][0][0];
                    dp[i][j][1][0] += dp[i-1][j-1][1][0];
                }
            }else{
                rep(l,2){
                    // 使わない
                    dp[i][j][0][l] += dp[i-1][j][0][l];
                    dp[i][j][0][l] += dp[i-1][j][1][l];
                    if(j>0){
                        // 前を使う
                        dp[i][j][0][l] += dp[i-1][j-1][0][l];
                        // 後ろを使う
                        dp[i][j][1][l] += dp[i-1][j-1][0][l];
                        dp[i][j][1][l] += dp[i-1][j-1][1][l];
                    }
                }
            }
        }
    }
    vector<mint> res(n+1, mint(0));
    rep(j,n+1){
        rep(k,2){
            rep(l,2){
                res[j] += dp[n][j][k][l];
            }
        }
    }
    return res;
}

int main(void){
    std::cin.tie(0)->sync_with_stdio(0);
    int N;cin>>N;
    vector<int> p(N),q(N);
    rep(i,N){cin>>p[i];p[i]--;}
    rep(i,N){cin>>q[i];q[i]--;}
    vector<vector<int>> G(N);    
    rep(i,N){
        G[p[i]].push_back(q[i]);
        G[q[i]].push_back(p[i]);
    }
    // サイクルを検出する
    vector<int> len(0); //i番目の連結成分の長さ
    vector<bool> used(N,false);
    rep(i,N){
        if(used[i])continue;
        int now=i;
        int cnt=0;
        int prev=-1;
        while(!used[now]){
            used[now]=true;
            cnt++;
            for(int next:G[now]){
                if(next==prev)continue;
                prev=now;
                now=next;
                break;
            }
        }
        len.push_back(cnt);
    }
    vector<mint> dp(N+1, mint(0));
    // dp[i] := i個の頂点を使ったときの場合の数
    dp[0] = 1;
    rep(j,len.size()){
        //cout<<len[j]<<"  "<<g[j]<<endl;
        vector<mint> g = f(len[j]);
        for(int i=N;i>=0;i--){
            for(int k=1;k<=len[j];k++){
                if(i-k<0)break;
                dp[i] += dp[i-k]*g[k];
            }
        }
    }
    vector<mint> fac(N+1, mint(0));
    fac[0] = 1;
    rep1(i,N){
        fac[i] = fac[i-1]*mint(i);
    }
    mint ans = fac[N];
    rep1(i,N){
        if(i%2==0){
            ans += dp[i]*fac[N-i];
        }else{
            ans -= dp[i]*fac[N-i];
        }
    }
    cout<<ans<<endl;
}

提出情報

提出日時
問題 G - Three Permutations
ユーザ shibaken496
言語 C++ 20 (gcc 12.2)
得点 600
コード長 8848 Byte
結果 AC
実行時間 364 ms
メモリ 285284 KiB

ジャッジ結果

セット名 Sample All
得点 / 配点 0 / 0 600 / 600
結果
AC × 3
AC × 31
セット名 テストケース
Sample example_00.txt, example_01.txt, example_02.txt
All corner_00.txt, corner_01.txt, cycle_00.txt, cycle_01.txt, cycle_02.txt, cycle_03.txt, cycle_04.txt, cycle_05.txt, example_00.txt, example_01.txt, example_02.txt, rand_00.txt, rand_01.txt, rand_02.txt, rand_03.txt, rand_04.txt, rand_05.txt, rand_06.txt, rand_07.txt, rand_08.txt, rand_09.txt, rand_10.txt, rand_11.txt, rand_12.txt, rand_13.txt, rand_14.txt, rand_15.txt, rand_16.txt, rand_17.txt, rand_18.txt, rand_19.txt
ケース名 結果 実行時間 メモリ
corner_00.txt AC 1 ms 3516 KiB
corner_01.txt AC 19 ms 3676 KiB
cycle_00.txt AC 164 ms 285084 KiB
cycle_01.txt AC 162 ms 285068 KiB
cycle_02.txt AC 114 ms 285088 KiB
cycle_03.txt AC 131 ms 284996 KiB
cycle_04.txt AC 117 ms 285176 KiB
cycle_05.txt AC 161 ms 285140 KiB
example_00.txt AC 120 ms 284912 KiB
example_01.txt AC 95 ms 284948 KiB
example_02.txt AC 146 ms 284756 KiB
rand_00.txt AC 311 ms 285124 KiB
rand_01.txt AC 328 ms 285124 KiB
rand_02.txt AC 289 ms 285284 KiB
rand_03.txt AC 364 ms 285128 KiB
rand_04.txt AC 264 ms 284968 KiB
rand_05.txt AC 291 ms 285104 KiB
rand_06.txt AC 308 ms 284980 KiB
rand_07.txt AC 231 ms 284860 KiB
rand_08.txt AC 222 ms 285064 KiB
rand_09.txt AC 122 ms 284864 KiB
rand_10.txt AC 257 ms 284944 KiB
rand_11.txt AC 250 ms 284828 KiB
rand_12.txt AC 171 ms 284776 KiB
rand_13.txt AC 208 ms 285020 KiB
rand_14.txt AC 278 ms 285044 KiB
rand_15.txt AC 225 ms 284868 KiB
rand_16.txt AC 302 ms 285108 KiB
rand_17.txt AC 311 ms 285044 KiB
rand_18.txt AC 138 ms 284936 KiB
rand_19.txt AC 211 ms 284988 KiB