---
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 << ' ';
}
}
```