单元格
题目
在一个 r ∗ c r*c r∗c的矩阵里选择三个点,使它们不在同行或同列,它们任意两点的曼哈顿距离在范围内,求方案数。
分析
首先对于每次的枚举,都可以转换成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]表示前j棵草剪了k次的总高度
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[j−1][k]+h[j]∗grow[j]∗i,f[j−1][k−1]+grow[j]∗(i−k))
代码
#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);
}