A.显然碰撞当且仅当编号相同,答案是编号相同的数量.
B.考虑差分数组可以发现答案是相邻差绝对值之和.枚举每个位置考虑把它修改成与它相邻的数后的答案.
C.考虑与坐标轴平行的边是同一行.
1.枚举每行最左边和最右边的(d),第(3)个点新增的点在第(1)行或第(n)行.
2.枚举每行的每个(d),第(2)的点是最上边或最下边的(d),第(3)个新增的点在这行最左边或最右边.
列的情况同理.
D.使用搜索引擎知道连续过(n)关的期望为(2^{n+1}-2).当(k)为奇数时无解,当(k)为偶数时每次贪心取最大的(n)构造即可.
upd:记连续过(n)关的的期望为(E_n),考虑递推式,(E_{n+1}=E_n+1+dfrac12E_{n+1}),即连续过完(n)关后,有一半概率再过一关即可,有一半概率需要从头再来.
考虑到(E_0=0),可以解出通项是(E_n=2^{n+1}-2).设计关卡时由于每两个检查点之间是独立的,期望就是各段期望之和.
E.可以发现序列是DFS序.(f[u])表示结点(u)到它子树中最近叶子距离.动态规划可以算出(f).
考虑每个非根非叶子结点,可以发现对其每个儿子(v)都要满足(kge f_v+2).
对于根节点,可以发现对其除至多一个儿子之外的每个儿子(v)都要满足(kge f_v+2).
最后还需要(kge f_1).
F.如果唯一路径是(u_1=1,u_2,cdots,u_m=n),那么要满足(u_{i+1}le u_i+a_{u_i}<u_{i+2}),并且对于所有(u_i<j<u_{i+1},j+a_j<u_{i+1}).
(dp[i][j][k])表示从(n)开始考虑到第(i)位,唯一路径后两个位置位(j)和(k)的最小代价.
两种转移.
1.(i)不在当前路径中,(dp[i][j][k]leftarrow dp[i+1][j][k]+[jle i+a_i]),因为(jle i+a_i)的时候,需要把第(i)位修改成(0),代价(+1).
2.(i)在当前路径中,(dp[i][i][j]leftarrow dp[i+1][j][k]),需要满足(jle i+a_i<k).
考虑维护二维矩阵(dp[][j][k]),对所有(i+1le jle i+a_i),第二种操作本质是(dp[][i][j]=min_{k>i+a_i}dp[][j][k]),第一种操作是(dp[][j][k])+=
(1).
upd:想要维护这两个操作,需要对每行求后缀最小值,以及进行整行(+1)的操作,下面代码中的dp数组实际上是dp数组的后缀最小值,add[j]
是对第一种对第(j)行(+1)操作进行标记.
代码可以这样写:
int n;
cin >> n;
vector<int> a(n + 1);
for(int i = 1; i <= n; i += 1) cin >> a[i];
vector<int> add(n + 1);
vector<vector<int>> dp(n + 1, vector<int>(n + 2, n));
dp[n][n + 1] = 0;
for(int i = n - 1; i >= 1; i -= 1)
for(int j = i + a[i]; j >= i + 1; j -= 1)
dp[i][j] = min(dp[i][j + 1], dp[j][i + a[i] + 1] + add[j] ++);
cout << dp[1][2] << "
";