---
# System prepended metadata

title: DDJ Regular Contest Round#7 Solution
tags: [DDJRC]

---

---
tags: DDJRC
---

# DDJ Regular Contest Round#7 Solution

[toc]

## 	[a618 A. 水題](http://203.64.191.163/ShowProblem?problemid=a617)

可以用set或者hash_table儲存有沒有寫過題目，再扣掉即可。
有個小陷阱是因為題目問說還要幾題，所以如果超過25%的話，要輸出0。

solution
```cpp=
unorder_map<string> mp;
int n;
string s;
cin >> n;
n = (n + 3) >> 2;
while(cin >> s){
  if(s == "0") break;
  mp[s] = 1;
  int tmp = mp.size();
  cout << (tmp > t ? n - t : 0) << '\n';
}
```

## [a634 B. 水有病毒題](http://203.64.191.163/ShowProblem?problemid=a634)

基本LCS做DP 8 次。(很噁心)
```cpp=
#include<bits/stdc++.h>
using namespace std;
string s[7];
int n;
int dp[10][10][10][10][10][10][10];
int in[7];
bool compare(){
  for(int i = 1; i < n; ++i)
    if(s[i - 1][in[i - 1] - 1] != s[i][in[i] - 1]) return false;
  return true;
}
int main(){
  cin >> n;
  for(int i = 0; i < n; ++i) cin >> s[i];
  memset(dp, 0, sizeof(dp));
  int size[7] = {0};
  for(int i = 0; i < n; ++i) size[i] = s[i].size();
  for(in[0] = 1; in[0] <= size[0]; ++in[0])
    for(in[1] = 1; in[1] <= size[1]; ++in[1])
      for(in[2] = (n >= 3); in[2] <= size[2]; ++in[2])
        for(in[3] = (n >= 4); in[3] <= size[3]; ++in[3])
          for(in[4] = (n >= 5); in[4] <= size[4]; ++in[4])
            for(in[5] = (n >= 6); in[5] <= size[5]; ++in[5])
              for(in[6] = (n >= 7); in[6] <= size[6]; ++in[6])
                if(compare()) dp[in[0]][in[1]][in[2]]
                                [in[3]][in[4]][in[5]][in[6]] = 
                              dp[in[0] - 1][in[1] - 1][in[2] - (in[2] > 0)]
                                [in[3] - (in[3] > 0)][in[4] - (in[4] > 0)]
                                [in[5] - (in[5] > 0)][in[6] - (in[6] > 0)] + 1;
                else{
                  dp[in[0]][in[1]][in[2]][in[3]][in[4]][in[5]][in[6]] =
                  max({
                    dp[in[0] - 1][in[1]][in[2]][in[3]][in[4]][in[5]][in[6]],
                    dp[in[0]][in[1] - 1][in[2]][in[3]][in[4]][in[5]][in[6]],
                    dp[in[0]][in[1]][in[2] - (in[2] > 0)][in[3]][in[4]][in[5]][in[6]],
                    dp[in[0]][in[1]][in[2]][in[3] - (in[3] > 0)][in[4]][in[5]][in[6]],
                    dp[in[0]][in[1]][in[2]][in[3]][in[4] - (in[4] > 0)][in[5]][in[6]],
                    dp[in[0]][in[1]][in[2]][in[3]][in[4]][in[5] - (in[5] > 0)][in[6]],
                    dp[in[0]][in[1]][in[2]][in[3]][in[4]][in[5]][in[6] - (in[6] > 0)],
                  });
                }
  cout << dp[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]] << '\n';
}
```
所以可以直接暴力搜尋就好。
(Code Author: benson0402)
```cpp=
vector<string> vec;
string chk;
bool dfs(int cur, int mx) {
  if(cur == mx) {
    for(auto& x : vec) {
      int i = 0;
      for(auto& c : x) if(i < mx && c == chk[i])
        ++i;
      if(i != mx) return false;
    }
    return true;
  }
  bool ret = 0;
  chk.push_back('A');
  ret = ret | dfs(cur + 1, mx);
  chk.pop_back();
  chk.push_back('T');
  ret = ret | dfs(cur + 1, mx);
  chk.pop_back();
  chk.push_back('C');
  ret = ret | dfs(cur + 1, mx);
  chk.pop_back();
  chk.push_back('G');
  ret = ret | dfs(cur + 1, mx);
  chk.pop_back();
  return ret;
}

int main(){
  ...
  for(int i = 0; i < n; ++i){
    if(dfs(0, i)){
      cout << i;
      return;
    }
  }
}
```

## [a638. C. 水還剩多少題](http://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a638)

整個流程基本上是：周圍跟底下先檔住，從上面灌水進去直到滿為止，再把底下打開讓水流掉。
並且也要考慮水流掉的時候會卡在凹槽，所以最後水的位置可能不會相連。

先利用dfs從上面開始搜尋，並計算出所有相連的空間有多少，這是第一步算出水能多滿。
接著從底面開始dfs往上搜尋，但這次的方向只會有上、前、後、左、右，不會往下搜尋，這樣可以算出會流掉多少水。
滿水 - 流走的水 = 最後剩餘的水

寫code的時候為了方便，把盒子上方跟下方再各加一層空間，就可以不用處理很多洞的情況(洞都都相連了)

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

int maze[110][110][110];
int dir[6][3] = {
  {-1, 0, 0}, //上
  {0, 1, 0},
  {0, -1, 0},
  {0, 0, 1},
  {0, 0, -1},
  {1, 0, 0} //下
};

int dfs(int x, int y, int z, int tar, int turn, int dirsel){
  int sum = 0;
  if(maze[x][y][z] == tar){
    sum++;
  }
  maze[x][y][z] = turn;

  for(int i = 0; i < dirsel; ++i){
    int dx = x+dir[i][0], dy = y+dir[i][1], dz = z+dir[i][2];
    if(maze[dx][dy][dz] == tar) sum += dfs(dx, dy, dz, tar, turn, dirsel);
  }
  return sum;
}

int main(){
  int n, m, s;
  while(cin >> n >> m >> s){
    memset(maze, 0, sizeof(maze));
    for(int i = 1; i <= m; ++i){
      for(int j = 1; j <= s; ++j){
        maze[1][i][j] = 1;
        maze[n+2][i][j] = 1;
      }
    }
    for(int i = 2; i <= n+1; ++i){
      for(int j = 1; j <= m; ++j){
        for(int k = 1; k <= s; ++k){
          cin >> maze[i][j][k];
        }
      }
    }
    int ans = dfs(1, 1, 1, 1, 2, 6);
    ans -= dfs(n+2, 1, 1, 2, 1, 5);
    ans -= dfs(1, 1, 1, 2, 1, 5); //上層新增的空間可能沒有流掉，dfs一次確保能處理掉
    cout << ans << '\n';
  }
}
```

## [a617 D. 青蛙喝水題](http://203.64.191.163/ShowProblem?problemid=a617)

BIT 

時間複雜度：O(nm + qlog(n)log(m))
```cpp=
#include<bits/stdc++.h>
#define ll long long
using namespace std;

const ll MOD = 27644437;
#define mod MOD
#define lowbit(x) (x&(-x))
const int N = 5005;
ll bit[N][N], pre[N][N], arr[N][N];
void init() {
  for(int i = 1; i < N; ++i)
    for(int j = 1; j < N; ++j)
      pre[i][j] = pre[i - 1][j] + pre[i][j - 1] - pre[i - 1][j - 1] + arr[i][j];
  for(int i = 1; i < N; ++i)
    for(int j = 1; j < N; ++j)
      bit[i][j] = pre[i][j] - pre[i - lowbit(i)][j] - pre[i][j - lowbit(j)] + pre[i - lowbit(i)][j - lowbit(j)];
}
void update(int x, int y, ll v){
  while(x < N){
    int ty = y;
    while(ty < N){
      bit[x][ty] = (v + bit[x][ty]) % MOD;
      ty += lowbit(ty);
    }
    x += lowbit(x);
  }
}

ll query(int x, int y){
  ll ret = 0;
  while(x){
    int ty = y;
    while(ty){
      ret = (bit[x][ty] + ret) % MOD;
      ty -= lowbit(ty);
    }
    x -= lowbit(x);
  }
  return ret;
}


int main() {
  int n, m, q; 
  cin >> n >> m >> q;
  memset(arr, 0, sizeof(arr));
  memset(bit, 0, sizeof(bit));
  memset(pre, 0, sizeof(pre));
  for(int i = 1; i <= n; ++i)
    for(int j = 1; j <= m; ++j)
      cin >> arr[i][j];
  init();
  while(q--){
    int x, y;
    ll ans;
    cin >> x >> y;
    ++x, ++y;
    ans =  (query(n, m) + query(x, y)
         - query(x, m) - query(n, y)) % mod;
    if(ans <= 0) ans += MOD;
    cout << ans % MOD << '\n';
    update(x, y, ans);
    ans = (ans + arr[x][y]) % MOD;
    arr[x][y] = ans;
  }
  for(int i = 1; i <= n; ++i)
    for(int j = 1; j <= m; ++j)
      cout << arr[i][j] << " \n"[j == m];
}
```

## [a635. E. 水很重要題](http://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a635)

整個水路圖是一個tree，由於需要找到調查地點往上數k次的地點，是一個kth ancestor的問題，用爆搜的話O(n^2)最糟情況會TLE，利用jump pointer algorithm(前處理跟查詢都是O(Nlgn))，得到每次查詢的目標，統計每個點出現幾次，再找出哪些點出現最多次。

AC程式碼：
```cpp=
#include<bits/stdc++.h>
using namespace std;

int jump[100005][105];

int main(){
  int n, q;
  int cnt[100005];
  cin >> n;
  memset(jump, 0, sizeof(jump));
  memset(cnt, 0, sizeof(cnt));
  for(int i = 0; i < n; ++i){
    int a, b;
    cin >> a >> b;
    jump[a][0] = b;
    if(a == b) jump[a][0] = 0;
  }
  for(int i = 1; i < __lg(n)+1; ++i){
    for(int j = 1; j <= n; ++j){
      jump[j][i] = jump[jump[j][i-1]][i-1];
    }
  }

  cin >> q;
  for(int i = 0; i < q; ++i){
    int a, k, bi = 0, ans;
    cin >> a >> k;
    ans = a;
    if(ans > n) ans = 0;
    while(k > 0){
      if(k & 1){
        if(ans == 0) break;
        ans = jump[ans][bi];
      }
      k >>= 1;
      bi++;
    }
    if(ans){
      cnt[ans]++;
      //cout << ans << ',';
    }
    //else cout << "No ans\n";
  }

  int maxn = 0;
  for(int i = 1; i <= n; ++i){
    maxn = max(maxn, cnt[i]);
  }
  for(int i = 1; i <= n; ++i){
    if(maxn == cnt[i]) cout << i << ' ';
  }
}
```