SSL 2393 SSL 2394 单元格 #模拟,动态规划#

本文解析了两道典型的算法竞赛题目,一是寻找特定条件下的矩阵点组合方案,二是通过动态规划解决草地修剪问题,确保总高度不超过限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

比赛


单元格

题目

在一个 r ∗ c r*c rc的矩阵里选择三个点,使它们不在同行或同列,它们任意两点的曼哈顿距离在范围内,求方案数。


分析

首先对于每次的枚举,都可以转换成6种方式,用一个answer(x)表示8~x的答案
用这种类似前缀和的方式,就可以求出答案,当然我列入dp


代码

#include <cstdio>
#define mod 1000000007
using namespace std;
long long r,c,mint,maxt,s1[4002],s2[4002];
long long answer(long long x){
	if (x<8) return 0;
	long long tmp,ans=0;
	for (int i=2;i<r;i++){
		int j=(x-2*i)/2;
		if (j<2) break;
		if (j+1>=c) tmp=6*(r-i)*(i-1)*s2[c-2]%mod;
		else tmp=6*(r-i)*(i-1)*(s1[j-1]*(c-j)+s2[j-2])%mod;//6种方式
	    ans=(ans+tmp)%mod;
	}
	return ans;
}
int main(){
	freopen("table.in","r",stdin);
	freopen("table.out","w",stdout);
	scanf("%lld%lld%lld%lld",&r,&c,&mint,&maxt);
	for (int i=1;i<=4001;i++) s1[i]=s1[i-1]+i,s2[i]=s2[i-1]+s1[i];
	printf("%lld",(answer(maxt)+mod-answer(mint-1))%mod);
	return 0;
}

剪草

题目

bessie剪草,每棵草都有生长速度,每次可以剪掉一棵草,但是下一刻还会重新长出来(每棵都会生长)。求什么时候才能使总高度不超过m


分析

如果剪了一棵再剪,无疑是浪费,所以最多剪n次。
如果n次不能完成,那就无解。
dp
先生长速度排序, f [ j ] [ k ] 表 示 前 j 棵 草 剪 了 k 次 的 总 高 度 f[j][k]表示前j棵草剪了k次的总高度 f[j][k]jk
f [ j ] [ k ] = min ⁡ ( f [ j − 1 ] [ k ] + h [ j ] ∗ g r o w [ j ] ∗ i , f [ j − 1 ] [ k − 1 ] + g r o w [ j ] ∗ ( i − k ) ) f[j][k]=\min(f[j-1][k]+h[j]*grow[j]*i, f[j-1][k-1]+grow[j]*(i-k)) f[j][k]=min(f[j1][k]+h[j]grow[j]i,f[j1][k1]+grow[j](ik))


代码

#include <cstdio>
#include <cctype>
using namespace std;
int n,m,h[52],grow[52],f[52][52];
void swap(int &a,int &b){a^=b; b^=a; a^=b;}
int min(int a,int b){return (a<b)?a:b;}
int in(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
int main(){
	freopen("grass.in","r",stdin);
	freopen("grass.out","w",stdout);
	n=in(); m=in();
    for (int i=1;i<=n;i++) h[i]=in();
    for (int i=1;i<=n;i++) grow[i]=in();
    for (int i=1;i<n;i++)
    for (int j=i+1;j<=n;j++)
    if (grow[i]>grow[j]) swap(grow[i],grow[j]),swap(h[i],h[j]);
	for (int i=0;i<=n;i++){
		for (int j=1;j<=n;j++){
			f[j][0]=f[j-1][0]+h[j]+grow[j]*i;
			for (int k=1;k<=i;k++) f[j][k]=2147483647;
		}
		for (int j=1;j<=n;j++)
		for (int k=1;k<=i;k++)
		f[j][k]=min(f[j-1][k]+h[j]+grow[j]*i,f[j-1][k-1]+grow[j]*(i-k));
		if (f[n][i]<=m) return !printf("%d",i);
	}
	return !printf("%d",-1);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值