得分:A 100,B 90,C 100,D 100 ,F 100
A,B,跳过
C ,前缀和维护一下,跳过
D,观察到T较小,情况较少,果断记忆化深搜,跳过
E题看起来比较复杂,代码量也较大,但各个部分都挺模板的;
先求连通块,在用宽搜求各连通块之间的最短距离,最后状压DP
(比赛打炸了,跳了)
F题感觉很简单,但老师说打出来的人不应该这么多,反而是E题过的人太少???
题目:给定n,p,求n的排序逆序对数<=p的方案
定义dp[i][j]为1~i的排序,方案数为k的方案;
考虑 i+1 的排列的转移方法,可以看作是在 i 的排列中插入 i+1
插在对头,贡献为 i ,依次类推,插在队尾贡献为 0
所以dp[i+1][j]可由dp[i][j-h]++dp[i][j]转移过来
代码:
dp[1][0]=1;
for(int i=2;i<=n;i++)
{
for(int j=0;j<=k;j++)
{
for(int h=0;h<=min(j,i-1);h++)
{
dp[i][j]+=dp[i-1][j-h];
}
}
}
但我们发现n^3会超时,同时也会发现第三层循环有明显的延续性,所以维护一段区间和
for(int i=2;i<=n;i++)
{
sum=0;
for(int j=0;j=i) sum=(sum+10000000007-dp[i-1][j-i])%10000000007;
dp[i][j]=sum%10000000007;
}
}
(代码块后怎么写正常内容???,不管写什么都在块里面???)
G题,也是求波峰波谷,跟昨天的DP很像,dp[i][2]表示以a[i]为结尾,波峰波谷的数量,sum[][]为前缀和。思路见昨天,直接放代码
for (int i=1;i<=n;i++)
{
long long cnt1=1;
long long cnt0=0;
for (int j=1;j<=m;j++)
{
dp[j][0]=dp[j][1]=0;
if (a[i]b[j])
{
dp[j][0]=cnt1;
dp[j][1]=cnt0;
ans=(ans+cnt1+cnt0)%mod;
}
else
{
if(b[j]<a[i])
{
cnt0=(cnt0+sum[j][0])%mod;
}
else
{
cnt1=(cnt1+sum[j][1])%mod;
}
}
}
for(int j=1;j<=m;j++)
{
if(b[j]a[i])
{
sum[j][0]=(sum[j][0]+dp[j][0])%mod;
sum[j][1]=(sum[j][1]+dp[j][1])%mod;
}
}
}
H题还没看