C. Arithmetic Progression
题意:有一列数,从小到大排列以后,你可以添加一个数,问你添加一个数以后,这个数列能不能变成等差数列,如果可以添加数,可以添加那几个
思路:对于n==1|| n == 2的时候直接特判,对于大于2的情况,把数列排序以后,找到数组中相差最小的数作为公差,在此遍历有几个地方不满足,然后讨论
代码:
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 7; int a[maxn]; int stk[maxn]; int top ; int main() { int n; scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); } sort(a + 1, a + 1 + n); if(n == 1){ puts("-1"); return 0; } if(a[1] == a[n]){ printf("1 "); printf("%d ",a[1]); return 0; } if(n == 2) { int len = a[2] - a[1]; if(len % 2 == 0) { printf("3 "); printf("%d %d %d ",a[1] - len, (a[1] + a[2]) / 2, a[2] + len); } else { printf("2 "); printf("%d %d ",a[1] - len, a[2] + len); } return 0; } int minn = 0x3f3f3f3f; for(int i = 2; i <= n; i++) { minn = min(minn, a[i] - a[i - 1]); } top = 0; for(int i = 1; i < n; i++) { if(a[i] + minn == a[i + 1])continue; stk[++top] = i; } if(top > 1){ puts("0"); } else if(top == 0) { printf("2 "); printf("%d %d ",a[1] - minn, a[n] + minn); } else { if(a[stk[1]] + 2 * minn == a[stk[1] + 1]){ printf("1 "); printf("%d ",a[stk[1]] + minn); } else { printf("0 "); } } return 0; }
D. Ksenia and Pawns
题意:有一张n*m的地图(2000)只有><^v# 5 中符号,#的位置可以放两个棋子,#上的棋子都不可以移动,其他符号上的棋子可以按照方向移动一格,现在你有两个棋子,问最多两个棋子可以一共移动多少步
思路:枚举每个#作为两颗棋子最后的终点,反向向回推,维护每天路的最大值,以及全局的最大值和次大值,如果全局最大值和次大值相等,答案就是二倍的最大值,否则答案是最大值*2 – 1,即放两个相邻的棋子,走到最后
代码:
#include <bits/stdc++.h> using namespace std; const int maxn = 2007; int n, m; char mp[maxn][maxn]; int max1, max2; int cnt; int dx[10] = {0, 0, 1, -1}; int dy[10] = {-1, 1, 0, 0}; char s[10] = {'>', '<', '^', 'v'}; void Max(int x) { if(x > max1) { max1 = x; } else if(x > max2) { max2 = x; } } int dfs(int x, int y) { int ans = 0; cnt ++; for(int i = 0; i < 4; i++) { int xx = dx[i] + x, yy = dy[i] + y; if(xx < 1 || xx > n || yy < 1 || yy > m || (mp[xx][yy] != s[i]))continue; if(mp[x][y] == '#') Max(dfs(xx, yy)); else ans = max(ans, dfs(xx, yy)); } return ans + 1; } int main() { scanf("%d%d%", &n, &m); for(int i = 1;i <= n; i++) { for(int j = 1; j <= m; j++) { cin >> mp[i][j]; } } max1 = 0, max2 = 0; cnt = 0; for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { if(mp[i][j] == '#') { dfs(i, j); } } } if(cnt < n * m) { puts("-1"); } else { printf("%d ",max1 == max2 ? max1 * 2: max1 * 2 - 1); } return 0; }
E. Ksenia and Combinatorics
题意:有n(50)个点,让你构造出一个树满足下列条件,
1有n个点,标号为1~n
2根的度数最多为2,除了根之外的点的度数最多为3
3树的最大匹配数不超过k
问能构造出多少颗,答案对1e9+7取模
思路:定义dp[i][j][0|1]表示用i个点,构造最大匹配数为j的dp[i][j][0]表示没有子节点连接根,[1]表示有子节点连接根,然后枚举树的左节点个数和右节点个数,以及左右节点是否是连接根的
dp[i][j][0] += dp[l][k][1] * dp[r][j – k][1] * res
dp[i][j][1] += dp[l][k][1] * dp[r][j – k -1] [0]* res
dp[i][j][1] += dp[l][k][0] * dp[r][j – k -1] [1]* res
dp[i][j][1] += dp[l][k][0] * dp[r][j – k -1] [0]* res
代码:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int maxn = 57; const int MOD = 1e9 + 7; const int inv2 = 500000004; int c[maxn][maxn]; int n, k; LL dp[maxn][maxn][2]; LL mod(LL x) { if(x >= MOD) return x % MOD; return x; } int main() { c[0][0] = 1; for(int i = 1; i <= 50; i++) { c[i][0] = c[i][i] = 1; for(int j = 1; j < i; j++) { c[i][j] = mod(c[i - 1][j - 1] + c[i - 1][j]); } } scanf("%d%d", &n, &k); if(k > n/2){ printf("0 "); return 0; } dp[1][0][0] = dp[0][0][1] = 1; for(int i = 1; i <= n; i++) { for(int j = 0; j <= k; j++) { for(int l = 0,r = i - 1; l <= r; l++, r--) { for(int k = 0; k <= j; k++) { LL res = 1; res = c[i - 1][l]; if(l == r) res = mod(res * inv2); if(l) res = mod(mod(res * l) * r); else res = mod(res * r); dp[i][j][0] = mod(dp[i][j][0] + mod(mod(dp[l][k][1] * dp[r][j - k][1]) * res)); if(k < j) { dp[i][j][1] = mod(dp[i][j][1] + mod(mod(dp[l][k][1] * dp[r][j - k - 1][0]) * res)); dp[i][j][1] = mod(dp[i][j][1] + mod(mod(dp[l][k][0] * dp[r][j - k - 1][1]) * res)); dp[i][j][1] = mod(dp[i][j][1] + mod(mod(dp[l][k][0] * dp[r][j - k - 1][0]) * res)); } } } } } printf("%d ",mod(dp[n][k][0] + dp[n][k][1])); return 0; }