塔防(cover)Atcoder/Codeforces的某道题
题目背景
在某个塔防游戏中,有一种防御塔,可以攻击到上下左右四个方向以及自身位置的敌人。
题目描述
塔防游戏的一个关卡地图可以看作一个
的矩阵,也就是 行, 列的矩阵。 其中,用
#
代表障碍,用.
代表地面。对于每个地面,都可以选择不放置防御塔,或者放置防御塔。每个防御塔能够攻击到自己所在位置的地面,同时,能攻击到自己位置上下左右四个射线方向上的敌人,攻击范围沿射线方向延伸。但是射线上如果有其他防御塔或者障碍,将会阻断攻击范围的延伸。现在,
决定随机放置防御塔。也就是说,对每个地面位置,是否放置防御塔是等概率的。 请求出这样随机放置防御塔后,期望有多少个地面位置能处于防御塔的攻击范围之下。
输出一个整数作为答案,表示答案在模
的意义下的结果。 输入格式
第一行,两个正整数
, 。 接下来
行,每行一个长度为 的字符串(表示地图)。 输出格式
输出一个整数作为答案,表示答案在模
的意义下的结果。 样例输入与输出
样例输入1
1 3 .#.
样例输出1
1
样例输入2
2 3 ..# #..
样例输出2
250000005
样例输入3
1 5 ..#..
样例输出3
3
提示与说明
样例1解释
随机放置一共有
种等概率可能: .#.
,t#.
,.#t
,t#t
,对应的攻击范围下的地面数量为, , , 。因此期望为 数据范围
对
的数据满足 , 对
的数据满足 , 对
的数据满足 。 时间限制:1s 空间限制:256MB
解题思路
首先我们来考虑什么情况下这个地面时不会被攻击到的:

每一个地面放置防御塔的概率都是.
都是没有放置的防御塔的时候,中间的地面才不会被攻击到。所以我们可以算出这个点不被攻击到的概率是
那么反过来说,这个点能够被攻击到的概率就是
最后,我们就只需要算出每个点的概率的和就是期望值了。
另一个考点:有理数取模
这道题里面给出的模数为
这道题中,我们只用求出逆元就可以了。我们先把分数
总体思路就是这样了,下面是一些优化和具体实现。
优化
找到每一个点对应的行和列里面有多少个没有被挡住的地面有两种方法,第一种就是非常暴力的枚举每一个点,并求出对应的地面数量。这种做法可以过掉所有数据点(因为没有
然而发现优化后在老年评测机上还是会
最后放上代码
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int read(){
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
void write(int x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
return ;
}
int qpow(int x,int up){
int result=1;
for(;up;up>>=1){
if(up&1) result=(long long)result*x%mod;
x=(long long)x*x%mod;
}
return result;
}
struct point{
int h;
int l;
}a[2005][2005];
int n,m,ans=0,pow2[4005];
char mmap[2005][2005],c;
int main(){
freopen("cover.in","r",stdin);
freopen("cover.out","w",stdout);
for(int i=1;i<=4000;i++){
pow2[i]=qpow(2,i);
}
n=read();
m=read();
for(int i=1;i<=n;i++){
c=getchar();
while(c!='#'&&c!='.') c=getchar();
mmap[i][1]=c;
for(int j=2;j<=m;j++){
mmap[i][j]=getchar();
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j].h==0){
bool flag1=0;
int pos1=m;
for(int k=j;k<=m;k++){
if(mmap[i][k]=='#'){
flag1=1;
pos1=k;
break;
}
}
if(flag1==1){
a[i][j].h=pos1-j;
}
else{
a[i][j].h=pos1-j+1;
}
if(flag1==1){
for(int k=j;k<pos1;k++){
a[i][k].h=a[i][j].h;
}
}
else{
for(int k=j;k<=pos1;k++){
a[i][k].h=a[i][j].h;
}
}
}
if(a[i][j].l==0){
bool flag2=0;
int pos2=n;
for(int k=i;k<=n;k++){
if(mmap[k][j]=='#'){
flag2=1;
pos2=k;
break;
}
}
if(flag2==1){
a[i][j].l=pos2-i;
}
else{
a[i][j].l=pos2-i+1;
}
if(flag2==1){
for(int k=i;k<pos2;k++){
a[k][j].l=a[i][j].l;
}
}
else{
for(int k=i;k<=pos2;k++){
a[k][j].l=a[i][j].l;
}
}
}
int tt=a[i][j].h+a[i][j].l-1;
ans=(ans+(long long)(pow2[tt]-1)*qpow(pow2[tt],mod-2)%mod)%mod;
}
}
write(ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步