Submission #588749

#TimeUsernameProblemLanguageResultExecution timeMemory
58874979brueStar Trek (CEOI20_startrek)C++17
100 / 100
222 ms34124 KiB
#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]; bitset<400002> mat; int ey[400002]; int parEdge[100002]; bitset<100002> canWin; bitset<400002> dfsChk; int group[100002], groupCnt[2]; int res[100002]; ll ans; bitset<100002> groupVisited; 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[400002][2]; int findV[100002][2]; bitset<400002> findChk[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=n; i<n+n; i++){ ey[i*2-2] = i-n+1; parEdge[i-n+1] = i*2-2; } 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 (stderr)

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);
      |         ~~~~~^~~~~~~~~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...