T1
题面:


水题,但要注意内存只有 16MB16MB16MB!因此不能开数组后再排序。
(代码自己写。)
T2
题面:


首先这题很好想的办法就是用 dfs 暴力枚举每一个数可能的值,然后看一看最终答案多少。
代码:
int dfs(int la,int x,int sum)
{
if(sum>m-1)
{
return 0;
}
if(x>n)
{
return c[n-1-sum][m-1-sum]%mod;
}
int ans=0;
for(int i=l[x];i<=r[x];i++)
{
if(i<=la)
{
ans=(ans+dfs(i,x+1,sum+1))%mod;
ans%=mod;
}
else
{
ans=(ans+dfs(i,x+1,sum))%mod;
ans%=mod;
}
}
return ans%mod;
}
这样你就拿到了 10pts10pts10pts。
然后我们在这个基础上套一个记忆化搜索,这样就可以拿到 50pts50pts50pts:
int dfs(int la,int x,int sum)
{
if(sum>m-1)
{
return 0;
}
if(x>n)
{
return c[n-1-sum][m-1-sum]%mod;
}
if(dp[la][x][sum]!=-1)
{
return dp[la][x][sum]%mod;
}
int ans=0;
for(int i=l[x];i<=r[x];i++)
{
if(i<=la)
{
ans=(ans+dfs(i,x+1,sum+1))%mod;
ans%=mod;
}
else
{
ans=(ans+dfs(i,x+1,sum))%mod;
ans%=mod;
}
}
return dp[la][x][sum]=ans%mod;
}
现在我来讲一讲满分做法。
既然 dfs 行不通,那我们就倒过来,换成 DP。
因为 dfs 带了三个参数,所以这个 DP 肯定也会带三个参数,即设 dp[i][j][k] 表示当前在第 iii 个数字,上一个数字是 jjj 且目前已经分成了 kkk 段的方案数。
读者可以自行试一试这个 DP 的转移,总之我写出来是一个起步 O(n4)O(n^4)O(n4) 的 DP,而且没法优化。
因此我们可以试着改变一下 DP 的定义:设 dp[i][j][k] 表示第 iii 个位置选了 jjj 这个数且目前已经分成了 kkk 段的方案数。
然后我们就可以分类讨论了:
- 如果第 iii 位要与第 i−1i-1i−1 位接上:那么前一个数必须小于 jjj,于是可以得出:dpi,j,k=∑p=1j−1dpi−1,p,kdp_{i,j,k}=\sum_{p=1}^{j-1}dp_{i-1,p,k}dpi,j,k=∑p=1j−1dpi−1,p,k。
- 如果第 iii 位要单独开一段:那么前一个数就随便选了,于是可以得到:dpi,j,k=∑p=1400dpi−1,p,k−1dp_{i,j,k}=\sum_{p=1}^{400}dp_{i-1,p,k-1}dpi,j,k=∑p=1400dpi−1,p,k−1(这里为了方便直接把上限设成了最大)。
综上,可以得到状态转移方程:
dpi,j,k=∑p=1j−1dpi−1,p,k+∑p=1400dpi−1,p,k−1dp_{i,j,k}=\sum_{p=1}^{j-1}dp_{i-1,p,k}+\sum_{p=1}^{400}dp_{i-1,p,k-1}dpi,j,k=p=1∑j−1dpi−1,p,k+p=1∑400dpi−1,p,k−1
因为这个方程里面只涉及 iii 与 i−1i-1i−1 的值,所以可以用滚动数组优化,则得到:
dpx,j,k=∑p=1j−1dpx⊕1,p,k+∑p=1400dpx⊕1,p,k−1dp_{x,j,k}=\sum_{p=1}^{j-1}dp_{x\oplus1,p,k}+\sum_{p=1}^{400}dp_{x\oplus1,p,k-1}dpx,j,k=

最低0.47元/天 解锁文章
364

被折叠的 条评论
为什么被折叠?



