답안 #588752

# 제출 시각 아이디 문제 언어 결과 실행 시간 메모리
588752 2022-07-04T02:36:45 Z 79brue Star Trek (CEOI20_startrek) C++17
7 / 100
3 ms 5204 KB
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const ll MOD = 1000000007;

struct Matrix{
    int n, m;
    ll mat[2][2];
    Matrix(){}
    Matrix(int n, int m): n(n), m(m){
        for(int i=0; i<n; i++) for(int j=0; j<m; j++) mat[i][j] = 0;
    }

    Matrix operator*(const Matrix &r)const{
        assert(m == r.n);
        Matrix ret (n, r.m);
        for(int i=0; i<n; i++){
            for(int j=0; j<m; j++){
                for(int k=0; k<r.m; k++){
                    ret.mat[i][k] += mat[i][j] * r.mat[j][k];
                    ret.mat[i][k] %= MOD;
                }
            }
        }
        return ret;
    }
};

ll mpow(ll x, ll y){
    if(!y) return 1;
    if(y%2) return mpow(x, y-1) * x % MOD;
    ll tmp = mpow(x, y/2);
    return tmp*tmp%MOD;
}

Matrix BasicMatrix(int n, int m){
    Matrix mat (n, m);
    assert(n==m);
    for(int i=0; i<n; i++) mat.mat[i][i] = 1;
    return mat;
}

Matrix mpow(Matrix x, ll y){
    if(!y) return BasicMatrix(x.n, x.m);
    if(y&1) return mpow(x, y-1) * x;
    Matrix tmp = mpow(x, y/2);
    return tmp * tmp;
}

int n, lim;
ll k;
vector<int> link[100002][2];
bool mat[300002];
int ey[300002];
int parEdge[100002];
bool canWin[100002];
bool dfsChk[300002];

int group[100002], groupCnt[2];
int res[100002];
ll ans;

bool groupVisited[100002];
void groupDfs(int x, int p=-1){
    groupCnt[group[x]]++;
    groupVisited[x] = 1;
    for(auto y: link[x][0]){
        if(ey[y]==p || groupVisited[ey[y]]) continue;
        group[ey[y]] = !group[x];
        groupDfs(ey[y], x);
    }
}

int winCnt[100002];
bool dfs(int pe){
    if(dfsChk[pe]) return mat[pe];
    int x = ey[pe];
    mat[pe] = !!(winCnt[x] - (pe > lim ? 0 : (dfsChk[pe^1] && !mat[pe^1])));
    dfsChk[pe] = 1;
    vector<int> nLink;
    for(auto y: link[x][0]){
        if((y^pe)==1) nLink.push_back(y);
        else if(!dfs(y)) winCnt[x]++, mat[pe] = 1;
    }
    link[x][0].swap(nLink);
    return mat[pe];
}

int find1[300002][2];
int findV[100002][2];
bool findChk[300002][2];
int dfsFind(int pe, bool dp){ /// 무조건 지나야 하는 상대 차례 점 개수 찾기
    if(findChk[dp][pe]) return find1[pe][dp];
    int x = ey[pe];
    findChk[dp][pe] = 1;
    if(!dp){ /// my turn
        int cnt = 0;
        for(auto y: link[x][0]){
            if((y^1)!=pe && !mat[y]) cnt++;
        }
        if(cnt > 1) return find1[pe][dp] = 0;
        assert(cnt == 1);
        for(auto y: link[x][0]){
            if((y^1)!=pe && !mat[y]) return find1[pe][dp] = dfsFind(y, !dp);
        }
        exit(1);
    }
    else{ /// your turn
        int ret = 1 + findV[x][1] - ((pe>lim || !findChk[0][pe^1]) ? 0 : find1[pe^1][0]);
        vector<int> v;
        for(auto y: link[x][1]){
            if((y^1)==pe) v.push_back(y);
            else{
                int tmp = dfsFind(y, !dp);
                ret += tmp, findV[x][1] += tmp;
            }
        }
        link[x][1].swap(v);
        return find1[pe][dp] = ret;
    }
}

int main(){
//    freopen("input.txt", "r", stdin);
    scanf("%d %lld", &n, &k);
    lim = (n-1)*2-1;
    for(int i=1; i<n; i++){
        int x, y;
        scanf("%d %d", &x, &y);
        link[x][0].push_back(i*2-2);
        link[x][1].push_back(i*2-2);
        link[y][0].push_back(i*2-1);
        link[y][1].push_back(i*2-1);
        ey[i*2-2] = y;
        ey[i*2-1] = x;
    }
    for(int i=1; i<=n; i++){
        ey[lim+i] = i;
        parEdge[i] = lim+i;
    }

    groupDfs(1);
    for(int i=1; i<=n; i++){
        canWin[i] = dfs(parEdge[i]);
    }
    for(int i=1; i<=n; i++) link[i][0] = link[i][1];
    for(int i=1; i<=n; i++){
        if(canWin[i]) res[i] = groupCnt[!group[i]] - dfsFind(parEdge[i], 0);
        else res[i] = dfsFind(parEdge[i], 1);
    }

    Matrix first (1, 2);
    first.mat[0][0] = first.mat[0][1] = 0;
    for(int i=1; i<=n; i++){
        if(canWin[i]) first.mat[0][0]++;
        else first.mat[0][1]++;
    }

    Matrix multiplier (2, 2); /// 0: WIN, 1: LOSE
    for(int i=1; i<=n; i++){
        if(canWin[i]){
            multiplier.mat[0][0] = (multiplier.mat[0][0] + n) % MOD;
            multiplier.mat[1][0] = (multiplier.mat[1][0] + groupCnt[group[i]]) % MOD;
            multiplier.mat[1][0] = (multiplier.mat[1][0] + res[i]) % MOD;

            multiplier.mat[1][1] = (multiplier.mat[1][1] + n - groupCnt[group[i]] - res[i] + MOD)%MOD;
        }
        else{
            multiplier.mat[1][0] = (multiplier.mat[1][0] + res[i]) % MOD;

            multiplier.mat[0][1] = (multiplier.mat[0][1] + n) % MOD;
            multiplier.mat[1][1] = (multiplier.mat[1][1] + n - res[i]) % MOD;
        }
    }
    multiplier = mpow(multiplier, k-1);
    first = first * multiplier;
    ll Wsum = first.mat[0][0], Lsum = first.mat[0][1];
    ll ans = 0;
    if(canWin[1]){
        ans = (Wsum * n + Lsum * groupCnt[group[1]] + Lsum * res[1]) % MOD;
    }
    else ans = Lsum * res[1] % MOD;

    printf("%lld", ans);
}

Compilation message

startrek.cpp: In function 'int main()':
startrek.cpp:127:10: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
  127 |     scanf("%d %lld", &n, &k);
      |     ~~~~~^~~~~~~~~~~~~~~~~~~
startrek.cpp:131:14: warning: ignoring return value of 'int scanf(const char*, ...)' declared with attribute 'warn_unused_result' [-Wunused-result]
  131 |         scanf("%d %d", &x, &y);
      |         ~~~~~^~~~~~~~~~~~~~~~~
# 결과 실행 시간 메모리 Grader output
1 Correct 2 ms 4948 KB Output is correct
2 Incorrect 3 ms 5204 KB Output isn't correct
3 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Correct 2 ms 4948 KB Output is correct
2 Correct 2 ms 4948 KB Output is correct
3 Correct 3 ms 4948 KB Output is correct
4 Correct 2 ms 4948 KB Output is correct
5 Correct 3 ms 4964 KB Output is correct
# 결과 실행 시간 메모리 Grader output
1 Correct 3 ms 4948 KB Output is correct
2 Correct 2 ms 4948 KB Output is correct
3 Correct 3 ms 5076 KB Output is correct
4 Correct 3 ms 5076 KB Output is correct
5 Incorrect 3 ms 4948 KB Output isn't correct
6 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Correct 3 ms 4948 KB Output is correct
2 Correct 2 ms 4948 KB Output is correct
3 Correct 3 ms 5076 KB Output is correct
4 Correct 3 ms 5076 KB Output is correct
5 Incorrect 3 ms 4948 KB Output isn't correct
6 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Correct 3 ms 4948 KB Output is correct
2 Correct 2 ms 4948 KB Output is correct
3 Correct 3 ms 5076 KB Output is correct
4 Correct 3 ms 5076 KB Output is correct
5 Incorrect 3 ms 4948 KB Output isn't correct
6 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Correct 3 ms 4948 KB Output is correct
2 Correct 2 ms 4948 KB Output is correct
3 Correct 3 ms 5076 KB Output is correct
4 Correct 3 ms 5076 KB Output is correct
5 Incorrect 3 ms 4948 KB Output isn't correct
6 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Correct 3 ms 4948 KB Output is correct
2 Correct 2 ms 4948 KB Output is correct
3 Correct 3 ms 5076 KB Output is correct
4 Correct 3 ms 5076 KB Output is correct
5 Incorrect 3 ms 4948 KB Output isn't correct
6 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Correct 2 ms 4948 KB Output is correct
2 Incorrect 3 ms 5204 KB Output isn't correct
3 Halted 0 ms 0 KB -