呜呜呜~评测机炸锅!模拟赛爆零!!( >﹏<。)
T1.chess
题目大意:给出一个(n imes n)黑白棋盘,求将其中(k imes k)区域的黑棋变成白棋后,全是白棋的行数和列数之和。
这题(n,kle 2000),所以很显然只能使用(O(n^2))算法,所以算每一个点的贡献就成了一个不错的方式。
我们先从行来看,如果一行中有贡献,必要的条件就是两边的黑棋的距离必须小于k,而如果我们只看最两边的黑棋的话,会发现,有贡献的区域(即(k imes k)矩阵左上角在这个区域时答案会加一)是成矩形。所以我么就可以使用二维差分数组,计算答案。具体如下:
设第(i)行最左与最右的黑棋的纵坐标设为(l,r),所以矩阵左上角的纵坐标至少应为(r-k+1),最多不能超过(l),横坐标至少应为(i-k+1),最多不能超过(i)。所以设差分数组为(sum[i][j]):
[sum[i-k+1][r-k+1]+1,sum[i-k+1][l+1]-1
]
[sum[i+1][r-k+1]-1,sum[i+1][l+1]+1
]
然后算一算(sum)的前缀和取最大值就好了。
要注意的一点就是(i-k+1)等可能会小于(1),要与(1)取(max),以及可能会出现一行没有黑棋的情况,要特判。
小结:
解题关键:想到计算贡献与差分维护
芝士点:差分
其实也还是一道思维题啦!
手起,码落:
#include<bits/stdc++.h>
#define re register
using namespace std;
const int N=2005;
int n,k,s,sum[N][N],ans;
char ch[N][N];
int main()
{
scanf("%d%d",&n,&k);
for(re int i=1;i<=n;i++)scanf("%s",ch[i]+1);
for(re int i=1,l,r,yor;i<=n;i++)
{
yor=0,l=1,r=n;
for(re int j=1;j<=n;j++)
{
if(ch[i][j]=='B')
{
yor=1;
l=max(l,j-k+1);
r=min(r,j);
}
}
if(yor==0)s++;
if(r<l)continue;
sum[max(i-k+1,1)][l]++;
sum[max(i-k+1,1)][r+1]--;
sum[i+1][l]--;
sum[i+1][r+1]++;
}
for(re int i=1,l,r,yor;i<=n;i++)
{
yor=0,l=1,r=n;
for(re int j=1;j<=n;j++)
{
if(ch[j][i]=='B')
{
yor=1;
l=max(l,j-k+1);
r=min(r,j);
}
}
if(yor==0)s++;
if(r<l)continue;
sum[l][max(i-k+1,1)]++;
sum[r+1][max(i-k+1,1)]--;
sum[l][i+1]--;
sum[r+1][i+1]++;
}
// for(re int i=1;i<=n;i++)
// {
// for(re int j=1;j<=n;j++)printf("%d ",sum[i][j]);
// puts("");
// }
for(re int i=1;i<=n;i++)
for(re int j=1;j<=n;j++)
sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1],ans=max(ans,sum[i][j]);
printf("%d",ans+s);
return 0;
}
T2.sequence
一句话题意:求一个序列分成若干块后的最大极差之和。(极差为最大值减最小值
这题看似简单,其实!也并不难。。
直接上吧,(f[i])表示前(i)个数的最大极差之和。首先,显而易见的一点是:在一个单调序列中间的节点绝对不会是决策点,因为选择端点一定优于中间节点。所以我们就可以把中间节点去掉,直接与(f[i-1])和(f[i-2])达到(O(1))转移啦!
要注意这题因为某些不知明的原因,用了一种输入量也是极大的方式生成数据。但代码中还是正常输入。
小结:
解题关键:想到单调序列中间节点非决策点而优化时间。
芝士点:动态规划
感觉最近的思维题好多呀!
手起,码落:
#include<bits/stdc++.h>
#define re register
#define max(x,y) ((x)>(y)?(x):(y))
#define MOD 1073741824
using namespace std;
inline long long read()
{
re long long x=0,f=1;
re char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar())if(ch=='-')f*=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
return x*f;
}
const int N=10000005,M=500005;
int len;
long long n,aa[N],ans,a[N],f[N];
bool vis[N];
int main()
{
n=read();
for(re int i=1;i<=n;i++)aa[i]=read();
vis[1]=vis[n]=1;
for(re int i=2;i<n;i++)
{
if(aa[i]>=aa[i-1]&&aa[i]>=aa[i+1])vis[i]=1;
if(aa[i]<=aa[i-1]&&aa[i]<=aa[i+1])vis[i]=1;
}
for(re int i=1;i<=n;i++)if(vis[i])a[++len]=aa[i];
for(re int i=2;i<=len;i++)f[i]=max(f[i-1],f[i-2]+abs(a[i]-a[i-1]));
printf("%lld",f[len]);
return 0;
}