$T1$:$20$分暴力。直接计算每个点左右所能到达的最大值,因为有些点可能在之后会被填平,所以左右每个点都需要记录并排序。然后$dfs$枚举所有选择填平$k$个点的方案,计算即可。$O(max(C(20,i))n$2$)$
1 #include <bits/stdc++.h> 2 #define INF 0x3f3f3f3f 3 #define ll long long 4 using namespace std; 5 const int mod = 1e9 + 7; 6 int n, k, h[30], vis[30], q[30]; 7 ll ans; 8 struct Max {int maxl[30], maxr[30], maxln[30], maxrn[30];}stu[30]; 9 struct T {int x, num;}t[30]; 10 int cmp(T a, T b) {return a.x > b.x;} 11 void solve() 12 { 13 ll sum = 0; 14 for(int i = 1; i <= n; ++i) {h[i] = q[i]; if(vis[i]) h[i] = 0;} 15 for(int i = 1; i <= n; ++i) 16 { 17 int Maxl = 0, Maxr = 0; 18 for(int j = 1; j < i; ++j) if(!vis[stu[i].maxln[j]]) {Maxl = stu[i].maxl[j]; break;}; 19 for(int j = 1; j <= n - i; ++j) if(!vis[stu[i].maxrn[j]]) {Maxr = stu[i].maxr[j]; break;} 20 if(h[i] < Maxl && h[i] < Maxr) sum += (min(Maxl, Maxr) - h[i]); 21 } 22 if(sum % 2 == 0) ++ans; 23 return; 24 } 25 void dfs(int x, int num) 26 { 27 if(n - num < k - x) return; 28 if(x > k) {solve(); return;} 29 for(int i = num; i <= n; ++i) 30 { 31 if(!vis[i]) 32 { 33 vis[i] = 1; 34 dfs(x + 1, i + 1); 35 vis[i] = 0; 36 } 37 } 38 return; 39 } 40 int main() 41 { 42 freopen("rain.in", "r", stdin), freopen("rain.out", "w", stdout); 43 scanf("%d %d", &n, &k); 44 for(int i = 1; i <= n; ++i) scanf("%d", &h[i]), q[i] = h[i]; 45 for(int i = 1; i <= n; ++i) 46 { 47 int z = 0; 48 for(int j = 1; j < i; ++j) t[++z].x = h[j], t[z].num = j; 49 sort(t + 1, t + z + 1, cmp); 50 for(int j = 1; j <= z; ++j) stu[i].maxl[j] = t[j].x, stu[i].maxln[j] = t[j].num; 51 z = 0; 52 for(int j = n; j > i; --j) t[++z].x = h[j], t[z].num = j; 53 sort(t + 1, t + z + 1, cmp); 54 for(int j = 1; j <= z; ++j) stu[i].maxr[j] = t[j].x, stu[i].maxrn[j] = t[j].num; 55 } 56 dfs(1, 1); 57 printf("%lld", ans % mod); 58 return 0; 59 }
$T3$:$40$分暴力。对于每一行的每一块土地,挖掘机可以用钻头进行覆盖,贪心每次覆盖最左边的土地,计算即可。$O(hw$2$)$
1 #include <bits/stdc++.h> 2 #define INF 0x3f3f3f3f 3 using namespace std; 4 int h, w, k, q; 5 char s[20][100010]; 6 int solve(int d, int l, int r) 7 { 8 int ans = 0; 9 for(int i = 1; i <= d; ++i) 10 for(int j = l; j <= r; ++j) 11 if(s[i][j] == 'X') 12 ++ans, j = j + k - 1; 13 return ans; 14 } 15 int main() 16 { 17 freopen("blueshit.in", "r", stdin), freopen("blueshit.out", "w", stdout); 18 scanf("%d %d %d %d", &h, &w, &k, &q); 19 for(int i = 1; i <= h; ++i) scanf("%s", s[i] + 1); 20 for(int i = 1, d, l, r; i <= q; ++i) scanf("%d %d %d", &d, &l, &r), printf("%d ", solve(d, l, r)); 21 return 0; 22 }
$T4$:$20$分暴力,枚举$k$,再枚举$A$和$B$的每一个子串,通过记录$f[k][i][j]$表示长度为$k$且$A$中以$i$开头,$B$中以$j$开头谁获胜进行转移,预处理$f[0][i][j]$。$O(k|A||B|)$
1 #include <bits/stdc++.h> 2 #define INF 0x3f3f3f3f 3 using namespace std; 4 int lx, ly, f[110][110][110], wx, wy, wp, all; 5 char x[110], y[110]; 6 int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);} 7 int main() 8 { 9 freopen("game.in", "r", stdin), freopen("game.out", "w", stdout); 10 scanf("%s %s", x + 1, y + 1); 11 lx = strlen(x + 1), ly = strlen(y + 1); 12 for(int i = 1; i <= lx; ++i) 13 { 14 for(int j = 1; j <= ly; ++j) 15 { 16 if(x[i] < y[j]) f[0][i][j] = 1, ++wx; 17 else if(x[i] > y[j]) f[0][i][j] = -1, ++wy; 18 else f[0][i][j] = 0, ++wp; 19 } 20 } 21 all = wx + wy + wp; 22 printf("%d/%d %d/%d %d/%d ", wx / gcd(wx, all), all / gcd(wx, all), wp / gcd(wp, all), all / gcd(wp, all), wy / gcd(wy, all), all / gcd(wy, all)); 23 for(int k = 1; k < min(lx, ly); ++k) 24 { 25 wx = 0, wy = 0, wp = 0; 26 for(int i = 1, j = i + k; i <= lx && j <= lx; ++i, ++j) 27 { 28 for(int s = 1, t = s + k; s <= ly && t <= ly; ++s, ++t) 29 { 30 if(f[k - 1][i][s] == 1) ++wx, f[k][i][s] = 1; 31 else if(f[k - 1][i][s] == -1) ++wy, f[k][i][s] = -1; 32 else 33 { 34 if(x[j] < y[t]) ++wx, f[k][i][s] = 1; 35 else if(x[j] > y[t]) ++wy, f[k][i][s] = -1; 36 else ++wp, f[k][i][s] = 0; 37 } 38 } 39 } 40 all = wx + wy + wp; 41 printf("%d/%d %d/%d %d/%d ", wx / gcd(wx, all), all / gcd(wx, all), wp / gcd(wp, all), all / gcd(wp, all), wy / gcd(wy, all), all / gcd(wy, all)); 42 } 43 return 0; 44 }